线程的属性:
我们知道,在创建一个线程的时候可以指定一个线程的属性,通过第二个参数来指定:pthread_attr_t *attr.
一般情况下,我们都将这个参数设置为空,表示这个线程使用的是默认属性
那么如果,我们要将线程属性设定为一个特定的值的话,这时候:我们就需要一个线程属性变量(类型:pthread_attr_t),这种类型的变量需要首先初始化后才能用,可以调用这个函数(pthread_attr_init)
要销毁这样的变量的话:pthread_attr_destroy
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
一旦我们初始化一个属性变量后,那么这个线程属性变量就包含了线程的多种属性的初始值(默认的)
1,获取与设置分离属性
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);//更改分离属性的默认值
attr:为刚才所初始化的线程属性变量(对于分离属性而言,还是默认值),
detachstat:我们可以通过改变这个值来达到更改默认默认值的作用
我们继续看看detachstat可以为那些值:PTHREAD_CREATE_DETACHED(表示线程的属性是分离的)
PTHREAD_CREATE_JOINABLE(表示线程的分离属性不是分离的,同样这也是默认值)
如果,一开始我们的属性是:不分离的话,也就是采取了默认值的话,就意味着我们的线程程序必须调用
pthread_join来避免僵线程的产生。。。。。
如果一开始我们的线程属性是分离的话,那么即使我们不来调用pthread_join也不会产生僵线程。。。。。。
同样的,我们也可以不去设置属性,在线程函数里面去调用detach函数来避免僵线程的产生。。。。。
2,获取与设置栈的大小
#include <pthread.h>
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
//第二个参数为0的话,表示使用系统定义的栈大小,如果我们自己设置的话,可能会导致一些移植性的问题
//所以通常情况下,我们不会去设置栈的大小,除非有特殊需求
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
3,获取和设置栈溢出保护区的大小
#include <pthread.h>
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
//默认的大小是4096k
4,获取与设置线程竞争范围
#include <pthread.h>
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(pthread_attr_t *attr, int *scope);
//默认值是系统范围的竞争
5,线程的调度策略
#include <pthread.h>
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);
6,继承的调度策略
#include <pthread.h>
int pthread_attr_setinheritsched(pthread_attr_t *attr,
int inheritsched);
int pthread_attr_getinheritsched(pthread_attr_t *attr,
int *inheritsched);
这意味着新创建的线程和调用它的线程是不是一样的调度策略
如果,我们设置成继承,就是一样的调度策略
7,设置或者获取调度参数
#include <pthread.h>
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);
其中:第二个参数是一个结构体:
我们只关心其中的一个参数(param.sched_priority)线程的优先级
8,设置或者获取并发级别
#include <pthread.h>
int pthread_setconcurrency(int new_level);
//new level线程的并发级别,实际上,并不意味着,可并发的线程数是这些,仅仅只是一个并发级别
//并且仅在N:M线程模型中才有效,设置并发级别,仅仅只是给内核一个提示:提供给定级别数量的核心线程
//来映射用户线程是高效的而已。。。。。仅仅是一个提示,并不能保证内核一定按照这种方式来映射啊
int pthread_getconcurrency(void);
//Compile and link with -pthread.
我们获取到上面的值是0,表示内核按照自己默认的方式来映射。。。
简单程序:
#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\n");
size_t size;
pthread_attr_getstacksize(&attr, &size);
printf("stacksize:%d\n", (int)size);
pthread_attr_getguardsize(&attr, &size);
printf("guardsize:%d\n", (int)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");//调度需要自己设置
struct sched_param param;
pthread_attr_getschedparam(&attr, ¶m);
printf("sched_priority:%d\n", param.sched_priority);
pthread_attr_destroy(&attr);
int level;
level = pthread_getconcurrency();
printf("level:%d\n", level);
return 0;
}
运行结果:
线程的特定数据:
1,在单线程程序中,我们经常用到全局变量以实现多个函数共享数据
2,但是在多线程程序中,同样存在全局变量,只不过这个全局变量是为了多个线程所共享的
也就说明:其中一个线程如果改变了这个全局变量的话,那么其它线程调用的时候就得不到想要的结果了
3,有时候,我们需要的是一个线程范围的私有全局变量,即使改变也不会对其它线程产生影响
这个时候,POSIX通过维护一定的数据结构来解决这个问题,这个数据结构为:
TSD(Pthread_Specific Data)线程特定数据
我们来看看这个简单的模型:
两个线程(线程0,线程n)
每个线程都有自己的私有属性(线程号,堆栈,优先级等)
另外每个线程还有自己的特有数据(总共有128项,是通过key-> value的形式来访问的,默认情
况下,每个线程都有这128项,那么我们要使用其中的一项,我们首先要先创建一个key,首先从128
项中去查找,这些指针是不是都是空的,如果是空的话,那么说明我们找到了一个空的位置,我们就可以创建
一个key了)
如上:我们的线程中用的时key[1],也就是说:一个线程创建了一个key,那么其它的线程也得到了一个
key,也就是说:创建的这个key指针相当于全局指针变量,供所有的线程用
但是,这个全局指针变量指向的实际数据是不一样的,每个线程都有一个自己的特有数据,指向了不同的内存
这样的话,也就说明,一个线程改变这个数据并不会影响其它的线程的使用啊,,,,
为了实现特定的数据,我们用到了以下的函数:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
//第一个参数,如果在main的话,每个线程有的私有全局变量
//第二个参数,要销毁的实际指向的数据
int pthread_key_delete(pthread_key_t key);
//总的线程都执行完后,需要删除一开始创建的那个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;
程序如下:
#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)
pthread_key_t key_tsd;
//定义一个全局变量
typedef struct tsd
{
pthread_t tid;
char *str;
}tsd_t;
void destroy_routine(void *value)
{
printf("destory......\n");
free(value);
}
void *thread_routine(void *arg)
{
tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));
value->tid = pthread_self();
value->str = (char *)arg;
pthread_setspecific(key_tsd, value);
printf("%s setspecific %p\n", (char *)arg, value);
value = pthread_getspecific(key_tsd);
printf("tid = 0x%x str= %s\n", (int)value->tid, value->str);
sleep(2);
value = pthread_getspecific(key_tsd);
printf("tid = 0x%x str= %s\n", (int)value->tid, value->str);
return NULL;
}
int main(void)
{
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);
//当两个线程都执行完之后,我们就会删除key_tsd
pthread_key_delete(key_tsd);
//然后就会去执行:destroy_routine这个函数的
return 0;
}
运行结果:
可以分析分析,在延时了2秒之后,每个线程都能保留自己的数据,能保证不会被改变、
这就是线程的特定数据