Skip to content
On this page

Linux 线程操作


标签:linux/ipc  

pthread.h

Linux 目前主要使用的线程接口库是 NTPL:

new posix thread library

库的文件为 pthread.h ,函数基本以 pthread_ 开头。

编译的时候需要加上链接参数 -lpthread

这个库的函数在错误时不会重置errno ,需要手动赋值。

phtread_create()

线程创建

函数原型

c
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);

参数

@thread :是我们自己声明的 pid 变量,创建成功的话,函数会将 pid 保存其中。

@attr:指定线程分离还是结合的属性,目前弃用,使用 NULL 填写。

@start_routine 回调函数,是线程执行的任务。

@arg 传递给线程的参数,没有就填写NULL

返回

成功返回 0,错误返回错误码(不重置 errno)并不对 thread 参数修改。

示例

c
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void*
pthread_function(void* arg)
{
  while (1) {
    printf("thread is running...\n");
    sleep(1);
  }
}

void*
thread_exec(void* arg)
{
  int data = *(int*)arg;
  while (1) {
    printf("child thread 2 is running %d ...\n", data);
    sleep(1);
  }
}

int
main(int argc, char const* argv[])
{
  pthread_t pt1, pt2;
  int ret;
  int data = 100;

  ret = pthread_create(&pt1, NULL, pthread_function, NULL);
  if (ret != 0) {
    errno = ret;
    perror("pthread_create()");
    return -1;
  }

  ret = pthread_create(&pt2, NULL, thread_exec, (void*)&data);
  if (ret != 0) {
    errno = ret;
    perror("pthread_create()");
    return -1;
  }

  while (1) {
    printf("main thread is running...\n");
    sleep(1);
  }
  return 0;
}

[!tip] Tip

可以使用结构体传多个参数。

pthread_exit()

线程退出

函数原型

c
#include <pthread.h>
void pthread_exit(void *retval);

参数

@retval 线程结束的时候传出的地址,因为线程是通过回调函数的方式运行的,空间存在于栈中,所以该地址不应该是局部变量,应选择:

  1. 静态局部变量;
  2. 全局变量;
  3. 堆区变量。

返回

无返回值

关于主线程退出

  1. 主线程使用 return返回主函数或者exit关闭主线程,其所有子线程会立即终止;
  2. 主线程使用pthread_exit,进程不会退出,等所有子线程终止,主线程退出。

示例

pthread_join部分的示例

pthread_join()

合并已经终止的线程。类似线程的 wait ,函数会阻塞。

函数原型

c
int pthread_join(pthread_t thread, void **retval);

参数

@thread 线程的 tid

@retval 线程调用 pthread_exit 时候返回的值,不想接收,可以使用 NULL

注意点

  1. 任何线程都可以等待其他线程退出
  2. 等待的线程没有结束则阻塞
  3. 线程结束,资源没有回收,可以用该函数释放

示例

c
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void *thread_exec(void *arg) {
  // static int data = 100;       // 返回静态变量

  int *data = (int *)malloc(4);   // 返回堆区变量
  *data = 50;

  // char *p = "hello";           // 返回只读区变量
  while (1) {
    printf("child thread is running ... \n");
    sleep(1);
    pthread_exit(data);
    // pthread_exit(p);
  }
}

int main(int argc, char const *argv[]) {
  pthread_t tid;
  int ret;
  // char *retval;
  int *retval;

  ret = pthread_create(&tid, NULL, thread_exec, NULL);
  if (ret != 0) {
    errno = ret;
    perror("Fail to pthread_create");
    return -1;
  }

  while (1) {
    printf("main thread is running ...\n");
    pthread_join(tid, (void**)&retval);
    printf("retval: %d\n", *retval);
    // printf("retval: %s\n", retval);
    sleep(5);
  }
  return 0;
}

pthread_detach()

线程分为结合式和分离式,通过 pthread_create创建的线程是结合式的,它的特点是,子线程退出的时候,需要主线程释放资源,而分离式的则会有系统自动释放。这个函数可以用于分离结合式的线程。

函数原型

c
int pthread_detach(pthread_t thread);

示例

就不写了,主线程里创建子线程后调用 pthread_detach(tid),就不需要最后再用 join 回收了。

pthread_cancel()

取消一个线程,类似于发结束信号。

函数原型

c
int pthread_cancel(pthread_t thread);

pthread_exit 的区别在于,这个函数可以通过别的线程结束指定特定线程,相当于自杀和他杀的区别。因为是强制结束,所以也没有返回值了。

线程间通讯

Linux 线程间通信

练习

在主函数中创建一个数组 int a[5] = {10,20,30,40,50}在子线程中将数组循环打印出来。

c
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

struct array
{
  int a[5];
  int len;
};

void*
thread_show(void* arg)
{
  int i = 0;
  struct array* test = (struct array*)arg;
  printf("child thread is running ....\n");
  for (i = 0; i < test->len; i++) {
    printf("%d\t", test->a[i]);
  }
  printf("\n");
}

int
main(int argc, char const* argv[])
{
  struct array test;
  int i = 0;
  pthread_t tid;

  test.len = 5;

  for (i = 0; i < test.len; i++) {
    scanf("%d", &test.a[i]);
  }

  pthread_create(&tid, NULL, thread_show, (void*)&test);

  while (1) {
    printf("main thread is running ...\n");
    sleep(1);
  }
  return 0;
}

Last updated: