Linux多线程 --线程属性

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Alatebloomer/article/details/81941635

线程属性

初始化/销毁线程属性

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);

获取/设置线程分离属性

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

参数说明:

The following values may be specified in detachstate:

   PTHREAD_CREATE_DETACHED

Threads that are created using attr will be created in a detached state.

   PTHREAD_CREATE_JOINABLE

Threads that are created using attr will be created in a joinable state.

The  default  setting  of  the  detach  state  attribute  in  a  newly initialized threadattributes object is PTHREAD_CREATE_JOINABLE.

The pthread_attr_getdetachstate() returns  the  detach  state  attribute  of  the  threadattributes object attr in the buffer pointed to by detachstate.

线程栈大小

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);

DESCRIPTION

 The pthread_attr_setstacksize() function sets the stack  size  attribute  of  the  threadattributes object referred to by attr to the value specified 

in stacksize.(一般情况下该值我们设置为0,使用系统默认设置的线程栈大小,否则可能会引起程序的可移植性的问题)       The  stack  size  attribute determines the minimum size (in bytes) that will be allocatedfor threads created using the thread attributes object attr. The pthread_attr_getstacksize() function returns the stack size attribute of  the  threadattributes object referred to by attr in the buffer pointed to by stacksize.

线程栈溢出保护区大小

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);

线程竞争范围(进程范围内的竞争 or 系统范围内的竞争)

int pthread_attr_getscope(const pthread_attr_t *attr,int *contentionscope);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);

contentionscope:

   PTHREAD_SCOPE_SYSTEM    、  PTHREAD_SCOPE_PROCESS

线程调度策略

int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

The  supported  values  for  policy  are  SCHED_FIFO, SCHED_RR, and SCHED_OTHER, as below:

  SCHED_FIFO    a first-in, first-out policy(先进先出调度策略); 

  SCHED_RR      a round-robin policy(时间片轮转调度算法);

  SCHED_OTHER   the standard round-robin time-sharing policy(线程一旦开始运行,直到被抢占或者直到线程阻塞或停止为止);  默认这种

线程继承的调度策略

int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);

The following values may be specified in inheritsched:

  PTHREAD_INHERIT_SCHED(继承调度属性)    PTHREAD_EXPLICIT_SCHED(指定自己的调度属性)

线程调度参数(实际上我们一般只关心一个参数:线程的优先级,默认为0)

int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
//sched_param结构体
struct sched_param {
    int sched_priority;     /* Scheduling priority */
};

线程的并发级别

获取与设置并发级别

int pthread_setconcurrency(int new_level);
int pthread_getconcurrency(void);

并发级别仅在N:M线程模型中有效,设置并发级别,给内核一个提示:表示提供给定级别数量的核心线程来映射用户线程是高效的(仅仅是一个提示),默认为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");
 
	// 获得栈大小
    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;
}

绑定属性:

  Linux中采用“一对一”的线程机制,也就是一个用户线程对应一个内核线程。绑定属性就是指一个用户线程固定地分配给一个内核线程,因为CPU时间片的调度是面向内核线程(也就是轻量级进程)的,因此具有绑定属性的线程可以保证在需要的时候总有一个内核线程与之对应。而与之对应的非绑定属性就是指用户线程和内核线程的关系不是始终固定的,而是由系统来控制分配的。 

分离属性:

  分离属性是用来决定一个线程以什么样的方式来终止自己。在非分离情况下,当一个线程结束时,它所占用的系统资源并没有被释放,也就是没有真正的终止。只有当pthread_join()函数返回时,创建的线程才能释放自己占用的系统资源。而在分离属性情况下,一个线程结束时立即释放它所占有的系统资源。这里要注意的一点是,如果设置一个线程的分离属性,而这个线程运行又非常快,那么它很可能在pthread_create()函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用。

其他属性解释可参考http://www.cnblogs.com/Zoran-/p/5819280.html

 

线程特定数据


    (1)在单线程程序中,经常用到"全局变量"以实现多个函数间共享数据.
    (2)在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.
    (3)但有时应用程序设计中有必要提供线程私有的全局变量,仅仅在某个线程中有效,但却可以跨多个函数访问.(一个线程对全局变量的修改不影响其他线程)

    (4)POSIX线程库通过维护一定的数据结构来解决这个问题,这些数据结构称为(TSD).

当调用pthread_key_create 后会产生一个所有线程都可见的线程特定数据(TSD)的键值(如上图中所有的线程都会得到一个pkey[1]的值), 但是这个键所指向的真实数据却是不同的,虽然都是pkey[1], 但是他们并不是指向同一块内存,而是指向了只属于自己的实际数据, 因此, 如果线程0更改了pkey[1]所指向的数据, 而并不能够影像到线程n;

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 函数.

更多信息参考:https://blog.csdn.net/caigen1988/article/details/7901248

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_once_t once_control = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
#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_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;
}

猜你喜欢

转载自blog.csdn.net/Alatebloomer/article/details/81941635