文章

C pthread函数

C pthread函数

线程创建

1
2
3
4
int pthread_create(pthread_t * restrict tidp,
                    const pthread_attr_t * restrict attr, 
                    void *(* start_rm)(void *), 
                    void *restrict arg);

获取线程标识符

1
pthread_t pthread_self(void);
  • 例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
      #include <stdio.h>                             
      #include <pthread.h>
    
      void * run (void *args) {
          printf("pthread id = %d\n", pthread_self());
          return NULL;
      }
    
      int main() {
          int ret;
          pthread_t tid;
          ret = pthread_create(&tid, NULL, run, NULL);
          if (ret) {
              printf("pthread create error\n");
              return 1;
          }
          void *val;
          pthread_join(tid, &val);
          return 0;
      }
    

线程退出

1
void pthread_exit(void * rval_ptr);

rval_ptr 是线程结束时的返回值,可以由 pthread_join() 获取

线程退出方式: 1. 线程从线程函数中返回 2. 线程被另一个线程终止 3. 线程自己调用 pthread_exit() 函数

线程等待

1
int pthread_join(pthread_t tid, void ** rval_ptr);
  • 调用后,一直等待指定的线程结束才返回函数,被等待线程的资源会被收回

  • 例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
      void * run2 ( void *args) {
          int i = 0;
          while (i < 10) {
              i++;
              printf("pthread id = %d\n", pthread_self());
              if (i == 5) {
                  pthread_exit((void *)i);
                  // 也可以使用return来返回
                  // return (void *)i;
              }
          }
          return NULL;
      }
    
      int main() {
          int ret;
          pthread_t tid;
          ret = pthread_create(&tid, NULL, run2, NULL);
          if (ret) {
              printf("pthread create error\n");
              return 1;
          }
          void *val;
          pthread_join(tid, &val);
          printf("val = %d\n", val);
          return 0;
      }
    

线程清除

  • 正常退出 : 通过 pthread_exit()return 的方式返回
  • 非正常退出 : 其他线程的干预下或自身运行错误而退出

    1
    
      void pthread_cleanup_push(void (* rtn)(void *), void * arg);
    

    函数说明:将清除函数压入清除栈。 rtn 是清除函数, arg 是清除函数的参数

    1
    
      void pthread_cleanup_pop(int execute);
    

    函数说明:将清除函数弹出清除栈。执行到 pthread_cleanup_pop() 时,参数 execute 决定是否在弹出清除函数的同时执行该函数,非0时执行

    1
    
      int pthread_cancel(pthread_t thread);
    

    函数说明:取消线程,该函数在其他线程中调用,用来强行杀死指定的线程

    pthread_cleanup_pushpthread_cleanup_pop 之间程序段中的终止动作(包括正常退出和异常退出,不包括return),都将执行 pthread_cleanup_push 所指定的清理函数

  • 例3:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    
      void *clean (void *arg) {
          printf("cleanup: %s\n", (char *)arg);
          return (void *)0;
      }
    
      void *thr_fn1 (void *arg) {
          printf("thread 1 start\n");
          pthread_cleanup_push((void *)clean, "thread 1 first handler");
          pthread_cleanup_push((void *)clean, "thread 1 second handler");
          printf("thread 1 push complete\n");
    
          if (arg) {
              return ((void*)1);
          }
    
          pthread_cleanup_pop(0);
          pthread_cleanup_pop(0);
          return (void *)1;
      }
    
      void *thr_fn2 (void *arg) {
          printf("thread 2 start\n");
          pthread_cleanup_push((void *)clean, "thread 2 first handler");
          pthread_cleanup_push((void *)clean, "thread 2 second handler");
          printf("thread 2 push complete\n");
    
          if (arg) {
              pthread_exit((void*)2);
          }
    
          pthread_cleanup_pop(0);
          pthread_cleanup_pop(0);
          pthread_exit((void *)2);
      }
    
      int main() {
          int err;
          pthread_t tid1, tid2;
          void *tret;
    
          err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);
    
          if (err != 0) {
              printf("main1:error...\n");
              return -1;
          }
    
          err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);
            
          if (err != 0) {
              printf("main2:error...\n");
              return -1;
          }
    
          err = pthread_join(tid1, &tret);
    
          if (err != 0) {
              printf("main3:error...\n");
              return -1;
          }
    
          printf("thread 1 exit code %d\n", (int)tret);
    
          err = pthread_join(tid2, &tret);
    
          if (err != 0) {
              printf("main4:error...\n");
              return -1;
          }
    
          printf("thread 2 exit code %d\n", (int)tret);
    
          return 0;
      }
    
    

pthread_exit()用于线程退出,可以指定返回值,以便其他线程通过pthread_join()函数获取该线程的返回值。return,是函数返回,不一定是线程函数哦! 只有线程函数中return,线程才会退出;

pthread_exit()、return都可以用pthread_join()来接收返回值的,也就是说,对于pthread_join()函数来说是没有区别的;

pthread_cleanup_push()所指定的清理函数支持调用pthread_exit()退出线程和异常终止,不支持return;

pthread_exit()为直接杀死/退出当前进程,return则为退出当前函数,但是在g++编译器中,main中的return会被自动优化成exit(),所以在主函数中使用return会退出该进程所有线程的运行;

return会调用局部对象的析构函数,而pthread_exit()不会(线程本来就不建议用pthread_exit()这类方法自杀的,正确的方法是释放所申请的内存后return)。

本文由作者按照 CC BY 4.0 进行授权