一. 线程属性
(1) 初始化与销毁属性
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
(2)获取与设置分离属性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
(3) 获取与设置栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
(4)获取与设置栈溢出保护区大小
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
(5) 获取与设置线程在竞争范围
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(pthread_attr_t *attr, int *scope);
(6) 获取与设置调度策略
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);
(7)获取与设置继承的调度策略
int pthread_attr_setinheritsched(pthread_attr_t *attr,
int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t *attr,
int *inheritsched);
(8) 获取与设置调度参数
int pthread_attr_setschedparam(pthread_attr_t *attr,
const struct sched_param *param);
int pthread_attr_getschedparam(pthread_attr_t *attr,
struct sched_param *param);
(9) 获取与设置并发级别
int pthread_setconcurrency(int new_level);
int pthread_getconcurrency(void);
仅仅在N:线程模型中有效,设置并发级别,给内核一个提示: 表示提供给定级别数量的核心线程来映射用户线程是高效的.
#include <unistd.h> #include <sys/types.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) int main(void) { pthread_attr_t attr; pthread_attr_init(&attr); //获取与设置分离属性 int state; pthread_attr_getdetachstate(&attr, &state); if (state == PTHREAD_CREATE_JOINABLE) printf("detachstate:PTHREAD_CREATE_JOINABLE\n"); else if (state == PTHREAD_CREATE_DETACHED) printf("detachstate:PTHREAD_CREATE_DETACHED"); // 获得栈大小 size_t size; pthread_attr_getstacksize(&attr, &size); printf("stacksize:%d\n", size); // 获取与设置栈溢出保护区大小 pthread_attr_getguardsize(&attr, &size); printf("guardsize:%d\n", size); //获取与设置线程在竞争范围 int scope; pthread_attr_getscope(&attr, &scope); if (scope == PTHREAD_SCOPE_PROCESS) printf("scope:PTHREAD_SCOPE_PROCESS\n"); if (scope == PTHREAD_SCOPE_SYSTEM) printf("scope:PTHREAD_SCOPE_SYSTEM\n"); // 获取与设置调度策略 int policy; pthread_attr_getschedpolicy(&attr, &policy); if (policy == SCHED_FIFO) printf("policy:SCHED_FIFO\n"); else if (policy == SCHED_RR) printf("policy:SCHED_RR\n"); else if (policy == SCHED_OTHER) printf("policy:SCHED_OTHER\n"); // 获取与设置继承的调度策略 int inheritsched; pthread_attr_getinheritsched(&attr, &inheritsched); if (inheritsched == PTHREAD_INHERIT_SCHED) printf("inheritsched:PTHREAD_INHERIT_SCHED\n"); // 继承调用线程属性 else if (inheritsched == PTHREAD_EXPLICIT_SCHED) printf("inheritsched:PTHREAD_EXPLICIT_SCHED\n"); // 需要自己设置 // 获取与设置调度参数 struct sched_param param; pthread_attr_getschedparam(&attr, ¶m); printf("sched_priority:%d\n", param.sched_priority); pthread_attr_destroy(&attr); return 0; }
二. 线程特定数据
(1)在单线程程序中,经常用到"全局变量"以实现多个函数间共享数据.
(2)在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.
(3)但有时应用程序设计中有必要提供线程私有的全局变量,仅仅在某个线程中有效,但却可以跨多个函数访问.
(4)POSIX线程库通过维护一定的数据结构来解决这个问题,这些数据结构称为(TSD).
线程特定数据存在的意义
现在有一全局变量,所有线程都可以使用它,改变它的值。而如果每个线程希望能单独拥有它,那么就需要使用线程存储了。表面上看起来这是一个全局变量,所有线程都可以使用它,而它的值在每一个线程中又是单独存储的。这就是线程存储的意义。
1. 创建一个类型为 pthread_key_t 类型的变量。
2. 调用 pthread_key_create() 来创建该变量。该函数有两个参数,第一个参数就是上面声明的 pthread_key_t 变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成 NULL ,这样系统将调用默认的清理函数。
3. 当线程中需要存储特殊值的时候,可以调用 pthread_setspcific() 。该函数有两个参数,第一个为前面声明的 pthread_key_t 变量,第二个为 void* 变量,这样你可以存储任何类型的值。
4. 如果需要取出所存储的值,调用 pthread_getspecific() 。该函数的参数为前面提到的 pthread_key_t 变量,该函数返回 void * 类型的值。
当调用pthread_key_create 后会产生一个所有线程都可见的线程特定数据(TSD)的pthread_key_t 值,调用,虽然只有一个pthread_key_t,但每个线程的特定数据是独立的内存空间,当线程退出时会执行destructor 函数.
相关函数:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
int pthread_once(pthread_once_t *once_control,
void (*init_routine)(void));
pthread_once_t once_control = PTHREAD_ONCE_INIT;
tsd.c
#include <unistd.h> #include <sys/types.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) typedef struct tsd { pthread_t tid; char *str; } tsd_t; pthread_key_t key_tsd; pthread_once_t once_control = PTHREAD_ONCE_INIT; void destroy_routine(void *value) { printf("destory ...\n"); free(value); } void once_routine(void) { pthread_key_create(&key_tsd, destroy_routine); printf("key init ...\n"); } void *thread_routine(void *arg) { //pthread_key_create(&key_tsd,destroy_routine); //pthread_once(&once_control, once_routine); //保证once_routine只会调用一次 // 使用malloc分配内存 tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t)); value->tid = pthread_self(); // 填值ID value->str = (char *)arg;// 传递的字符串 //pthread_setspecific 后会将每个线程的特定数据与pthread_key_t 绑定起来 pthread_setspecific(key_tsd, value); printf("%s setspecific ptr=%p\n", (char *)arg, value); // 获取特定值 value = pthread_getspecific(key_tsd); printf("tid=0x%x str=%s ptr=%p\n", (int)value->tid, value->str, value); sleep(2); // 获取特定值 value = pthread_getspecific(key_tsd); printf("tid=0x%x str=%s ptr=%p\n", (int)value->tid, value->str, value); return NULL; } int main(void) { //当调用pthread_key_create 后会产生一个所有线程都可见的线程特定数据(TSD)的pthread_key_t 值 pthread_key_create(&key_tsd, destroy_routine); pthread_t tid1; pthread_t tid2; // 创建两个线程 pthread_create(&tid1, NULL, thread_routine, "thread1"); pthread_create(&tid2, NULL, thread_routine, "thread2"); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_key_delete(key_tsd); return 0; }
把64,42,43行的注释去掉,只有一个第一个进入的线程调用once_routine