您的位置:首页 > 其它

线程的基本属性(分离,栈大小,保护区,竞争,调度并发)以及TSD特定数据

2016-08-06 16:47 483 查看
线程的属性:

  我们知道,在创建一个线程的时候可以指定一个线程的属性,通过第二个参数来指定: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秒之后,每个线程都能保留自己的数据,能保证不会被改变、

这就是线程的特定数据
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: