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, ¶m); 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, ¶m); 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)即将退出…