【PTHREAD】线程创建

1 API

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

2 案例:默认值创建线程

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    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);
    }
    
  • 输出

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

3 案例:线程传参

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <string.h>
    
    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);
    }
    
  • 输出

    主线程(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 <pthread.h>
#include <time.h>

int pthread_getcpuclockid(pthread_t thread, clockid_t *clock_id);

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);

6 线程属性之调度优先级

int pthread_setschedprio(pthread_t thread, int prio);

7 案例:获取线程属性

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <string.h>
    #include <time.h>
    
    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);
    }
    
  • 输出

    主线程(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);
  • pthread_key_create

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

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

2.2.9 案例:私有数据的使用

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <string.h>
    
    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);
    }
    
  • 输出

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

10 判断线程ID是否相等

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

11 单次初始化

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

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

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <time.h>
    
    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);
    }
    
  • 输出

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值