• 【PTHREAD】线程创建


    1 API

    int pthread_create(pthread_t *thread,
                       const pthread_attr_t *attr,
                       void *(*start_routine) (void *),
                       void *arg);
    
    • 1
    • 2
    • 3
    • 4
    • 参数
      • thread
        线程的唯一标识。在线程内部使用pthread_self()获取。
      • attr
        线程属性。设置为NULL表示使用默认属性。
      • start_routime
        线程工作函数。类型为以void *为参数,并返回void *
      • arg
        传递给线程工作函数(start_routime)的数据指针。设置为NULL标识无需传递数据。

    2 案例:默认值创建线程

    • 源码

      #include 
      #include 
      #include 
      #include 
      
      void *start_routine(void *ptr)
      {
          printf("子线程(%lu)等待3秒后退出...\n", pthread_self());
          sleep(3);
          printf("子线程(%lu)即将退出...\n", pthread_self());
          return (void *)NULL;
      }
      
      int main(int argc, char const *argv[])
      {
          printf("主线程(%lu)开始运行...\n", pthread_self());
          pthread_t thread_id;
      
          {
              // 以默认线程属性,创建无数据传递的线程
              pthread_attr_t attr;
              pthread_attr_init(&attr);
              pthread_create(&thread_id, &attr, start_routine, NULL);
              pthread_attr_destroy(&attr);
      
              // 下面这条语句与上面的四条语句等价
              // pthread_create(&thread_id, NULL, start_routine, NULL);
          }
      
          printf("主线程(%lu)等待5秒后结束...\n", pthread_self());
          sleep(5);
      
          printf("主线程(%lu)即将退出...\n", pthread_self());
          exit(EXIT_SUCCESS);
      }
      
      • 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
    • 输出

      主线程(139943698245440)开始运行…
      主线程(139943698245440)等待5秒后结束…
      子线程(139943698241280)等待3秒后退出…
      子线程(139943698241280)即将退出…
      主线程(139943698245440)即将退出…

    3 案例:线程传参

    • 源码

      #include 
      #include 
      #include 
      #include 
      #include 
      
      typedef struct _student
      {
          int id;
          int age;
          char name[32];
      } student;
      
      void *start_routine(void *ptr)
      {
          printf("子线程(%lu)等待3秒后退出...\n", pthread_self());
          sleep(3);
          student *pstu = (student *)ptr;
          printf("子线程(%lu)接收的数据: name = %s, age = %d, id = %d\n",
                 pthread_self(), pstu->name, pstu->age, pstu->id);
          printf("子线程(%lu)即将退出...\n", pthread_self());
          return (void *)NULL;
      }
      
      int main(int argc, char const *argv[])
      {
          printf("主线程(%lu)开始运行...\n", pthread_self());
      
          student stu;
          bzero(&stu, sizeof(stu));
          strcpy(stu.name, "zhang san");
          stu.age = 18;
          stu.id = 2022;
      
          pthread_t thread_id;
          {
              printf("父线程(%lu)传递的数据: name = %s, age = %d, id = %d\n",
                     pthread_self(), stu.name, stu.age, stu.id);
              pthread_create(&thread_id, NULL, start_routine, &stu);
          }
      
          printf("主线程(%lu)等待5秒后结束...\n", pthread_self());
          sleep(5);
      
          printf("主线程(%lu)即将退出...\n", pthread_self());
          exit(EXIT_SUCCESS);
      }
      
      • 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
    • 输出

      主线程(139644495886144)开始运行…
      父线程(139644495886144)传递的数据: name = zhang san, age = 18, id = 2022
      主线程(139644495886144)等待5秒后结束…
      子线程(139644495881984)等待3秒后退出…
      子线程(139644495881984)接收的数据: name = zhang san, age = 18, id = 2022
      子线程(139644495881984)即将退出…
      主线程(139644495886144)即将退出…

    4 线程属性之CPU时钟

    #include 
    #include 
    
    int pthread_getcpuclockid(pthread_t thread, clockid_t *clock_id);
    
    • 1
    • 2
    • 3
    • 4

    5 线程属性之调度策略与调度参数

    int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param);
    int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
    
    • 1
    • 2

    6 线程属性之调度优先级

    int pthread_setschedprio(pthread_t thread, int prio);
    
    • 1

    7 案例:获取线程属性

    • 源码

      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      
      void *start_routine(void *ptr)
      {
          printf("子线程(%lu)等待3秒后退出...\n", pthread_self());
      
          clockid_t clock_id;
          pthread_getcpuclockid(pthread_self(), &clock_id);
          printf("子线程(%lu)的CPU时钟ID(%d)\n", pthread_self(), clock_id);
      
          int sched_policy;
          struct sched_param param;
          pthread_getschedparam(pthread_self(), &sched_policy, &param);
          printf("子线程(%lu)的调度策略(%s)\n", pthread_self(),
                 sched_policy == SCHED_FIFO ? "SCHED_FIFO" :
                 sched_policy == SCHED_RR  ? "SCHED_RR" :
                 sched_policy == SCHED_OTHER ? "SCHED_OTHER" : "???");
          printf("子线程(%lu)的调度优先级(%d)\n", pthread_self(), param.sched_priority);
      
          printf("子线程(%lu)即将退出...\n", pthread_self());
          return (void *)NULL;
      }
      
      int main(int argc, char const *argv[])
      {
          printf("主线程(%lu)开始运行...\n", pthread_self());
      
          pthread_t thread_id;
          pthread_create(&thread_id, NULL, start_routine, NULL);
      
          clockid_t clock_id;
          pthread_getcpuclockid(pthread_self(), &clock_id);
          printf("主线程(%lu)的CPU时钟ID(%d)\n", pthread_self(), clock_id);
      
          int sched_policy;
          struct sched_param param;
          pthread_getschedparam(pthread_self(), &sched_policy, &param);
          printf("主线程(%lu)的调度策略(%s)\n", pthread_self(),
                 sched_policy == SCHED_FIFO ? "SCHED_FIFO" :
                 sched_policy == SCHED_RR  ? "SCHED_RR" :
                 sched_policy == SCHED_OTHER ? "SCHED_OTHER" : "???");
          printf("主线程(%lu)的调度优先级(%d)\n", pthread_self(), param.sched_priority);
      
          printf("主线程(%lu)等待5秒后结束...\n", pthread_self());
          sleep(5);
      
          printf("主线程(%lu)即将退出...\n", pthread_self());
          exit(EXIT_SUCCESS);
      }
      
      • 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
    • 输出

      主线程(139759329433408)开始运行…
      主线程(139759329433408)的CPU时钟ID(-50154)
      子线程(139759329429248)等待3秒后退出…
      子线程(139759329429248)的CPU时钟ID(-50162)
      子线程(139759329429248)的调度策略(SCHED_OTHER)
      子线程(139759329429248)的调度优先级(0)
      子线程(139759329429248)即将退出…
      主线程(139759329433408)的调度策略(SCHED_OTHER)
      主线程(139759329433408)的调度优先级(0)
      主线程(139759329433408)等待5秒后结束…
      主线程(139759329433408)即将退出…

    8 线程属性之私有数据

    程序经常需要在不同的线程中使用全局或静态变量,这些变量不同的线程中拥有不同的值。由于同一个进程中的所有线程共享相同的内存空间,因此常规的变量无法实现该需求。

    为满足以上需求,提出了线程私有数据的概念。每个线程有一个私有的内存块,这个内存块就是线程的特有区域。该区域使用键值进行索引,使用void *类型。

    当创建一个线程时,所有的线程私有数据的键值均为NULL

    typedef unsigned int pthread_key_t;
    
    int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));
    int pthread_key_delete(pthread_key_t key);
    int pthread_setspecific(pthread_key_t key, const void *pointer);
    void * pthread_getspecific(pthread_key_t key);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • pthread_key_create

      • 用于创建一个新的键值。

      • 参数destr_function如果非NULL,指定与键值相关的析构函数。当线程通过pthread_exit或取消操作进行终结时,指定的析构函数被调用,其参数为键值对应的数据。如果赋值为NULL,则不进行调用。如果有多个键值对应的数据需要析构,则其调用的顺序是不确定的。

    2.2.9 案例:私有数据的使用

    • 源码

      #include 
      #include 
      #include 
      #include 
      #include 
      
      pthread_key_t key;
      
      void *start_routine(void *ptr)
      {
          printf("子线程(%lu)开始运行...\n", pthread_self());
          pthread_key_t key = *((pthread_key_t *)ptr);
      
          // 主线程向KEY中写入值
          int specific_data = 88;
          pthread_setspecific(key, &specific_data);
      
          sleep(3);
      
          // 主线程从KEY中获取值
          int *p_specific_data = pthread_getspecific(key);
          printf("主线程(%lu)的私有数据(%d), 地址(%p)\n", pthread_self(), *p_specific_data, p_specific_data);
      
          printf("子线程(%lu)即将退出...\n", pthread_self());
          return (void *)NULL;
      }
      
      int main(int argc, char const *argv[])
      {
          printf("主线程(%lu)开始运行...\n", pthread_self());
      
          // 初始化KEY
          pthread_key_create(&key, NULL);
      
          // 主线程向KEY中写入值
          int specific_data = 99;
          pthread_setspecific(key, &specific_data);
      
          pthread_t thread_id;
          pthread_create(&thread_id, NULL, start_routine, &key);
      
          // 主线程从KEY中获取值
          int *p_specific_data = pthread_getspecific(key);
          printf("主线程(%lu)的私有数据(%d), 地址(%p)\n", pthread_self(), *p_specific_data, p_specific_data);
      
          sleep(5);
      
          // 销毁KEY
          pthread_key_delete(key);
      
          printf("主线程(%lu)即将退出...\n", pthread_self());
          exit(EXIT_SUCCESS);
      }
      
      • 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
    • 输出

      主线程(140110147004224)开始运行…
      主线程(140110147004224)的私有数据(99), 地址(0x7ffe404081f4)
      子线程(140110147000064)开始运行…
      主线程(140110147000064)的私有数据(88), 地址(0x7f6def8a8ec8)
      子线程(140110147000064)即将退出…
      主线程(140110147004224)即将退出…

    10 判断线程ID是否相等

    int pthread_equal(pthread_t t1, pthread_t t2);
    
    • 1
    • 相等返回非零
    • 不等但会零

    11 单次初始化

    pthread_once_t once_control = PTHREAD_ONCE_INIT;
    int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
    
    • 1
    • 2
    • 用于保证参数init_routine中的代码最多执行一次

    13 案例:单次初始化的使用

    • 源码

      #include 
      #include 
      #include 
      #include 
      #include 
      
      pthread_once_t once = PTHREAD_ONCE_INIT;
      
      void init_routine(void)
      {
          printf("线程(%lu)执行初始化\n", pthread_self());
      }
      
      
      void *start_routine(void *ptr)
      {
          printf("子线程(%lu)开始运行...\n", pthread_self());
          pthread_once(&once, init_routine);
          printf("子线程(%lu)即将退出...\n", pthread_self());
          return (void*)"9999";
      }
      
      int main(int argc, char const *argv[])
      {
          printf("主线程(%lu)开始运行...\n", pthread_self());
          
          pthread_t thread_id_01;
          pthread_create(&thread_id_01, NULL, start_routine, NULL);
      
          pthread_t thread_id_02;
          pthread_create(&thread_id_02, NULL, start_routine, NULL);
      
          printf("主线程(%lu)即将退出...\n", pthread_self());
          exit(EXIT_SUCCESS);
      }
      
      • 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
    • 输出

      主线程(140486961612608)开始运行…
      子线程(140486961608448)开始运行…
      线程(140486961608448)执行初始化
      子线程(140486961608448)即将退出…
      主线程(140486961612608)即将退出…

  • 相关阅读:
    Mysql进阶索引篇03——2个新特性,11+7条设计原则教你创建索引
    redis的原理和源码-缓存的三个常见问题(缓存穿透、缓存击穿、缓存雪崩)
    pytorch中的seq2seq的人们国籍分类的示例
    fastjson 1.2.47 远程命令执行漏洞
    gem5 编译与环境搭建
    牛客SQL必会知识
    七、 循环
    STC单片机定时器0手动状态脉冲定时器2自动状态脉冲加减速控制
    如何获取用户的ip地址
    如何用手机连接无线网络
  • 原文地址:https://blog.csdn.net/zhy29563/article/details/126669944