POSIX线程(二)

一. 线程属性
    (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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值