线程属性-pthread_attr_init

我们一般创建线程是这样

pthread_t tid;

pthread_create(&tid, NULL, func, NULL);

第二个参数是线程属性设置,一般设置为了NULL,但是可以通过系统API进一步设置第二个参数,细化创建的线程的属性。

大致步骤为:

pthread_attr_t attr;

pthread_attr_init(&attr);

pthread_attr_setXXX(&attr, 目标值);

……//创建线程,其他代码

线程属性

1.线程属性

​ 线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。我们用pthread_attr_init函数对其初始化,用pthread_attr_destroy对其去除初始化。

1

名称: 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);*
参数: Attr 线程属性变量
返回值: 若成功返回0,若失败返回-1

调用pthread_attr_init之后,pthread_t结构所包含的内容就是操作系统实现支持的线程所有属性的默认值。

如果要去除对pthread_attr_t结构的初始化,可以调用pthread_attr_destroy函数。如果pthread_attr_init实现时为属性对象分配了动态内存空间,pthread_attr_destroy还会用无效的值初始化属性对象,因此如果经pthread_attr_destroy去除初始化之后的pthread_attr_t结构被pthread_create函数调用,将会导致其返回错误。

线程属性结构如下:

typedef struct

{

int detachstate; 线程的分离状态

int schedpolicy; 线程调度策略

structsched_param schedparam; 线程的调度参数

int inheritsched; 线程的继承性

int scope; 线程的作用域

size_t guardsize; 线程栈末尾的警戒缓冲区大小

int stackaddr_set;

void\ stackaddr;* 线程栈的位置

size_t stacksize; 线程栈的大小

}pthread_attr_t;

每个个属性都对应一些函数对其查看或修改。下面我们分别介绍。

二、线程的分离状态

​ 线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。

而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。所以如果我们在创建线程时就知道不需要了解线程的终止状态,则可以pthread_attr_t结构中的detachstate线程属性,让线程以分离状态启动。

2

名称: pthread_attr_getdetachstate/pthread_attr_setdetachstate
功能: 获取/修改线程的分离状态属性
头文件: #include<pthread.h>
函数原形: int pthread_attr_getdetachstate(const pthread_attr_t \attr,int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr,intdetachstate);*
参数: Attr 线程属性变量Detachstate 线程的分离状态属性
返回值: 若成功返回0,若失败返回-1

可以使用pthread_attr_setdetachstate函数把线程属性detachstate设置为下面的两个合法值之一:设置为PTHREAD_CREATE_DETACHED,以分离状态启动线程;或者设置为PTHREAD_CREATE_JOINABLE,正常启动线程。可以使用pthread_attr_getdetachstate函数获取当前的datachstate线程属性。

以分离状态创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<pthread.h>
void *child_thread(void *arg)
{
printf(“child thread run!\n”);
}
int main(int argc,char *argv[ ])
{
pthread_ttid;
pthread_attr_tattr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//分离
pthread_create(&tid,&attr,fn,arg);
pthread_attr_destroy(&attr);
sleep(1);
}

三、线程的继承性

​ 函数pthread_attr_setinheritschedpthread_attr_getinheritsched分别用来设置和得到线程的继承性,这两个函数的定义如下:

3.

名称: pthread_attr_getinheritsched**pthread_attr_setinheritsched
功能: 获得/设置线程的继承性
头文件: #include<pthread.h>
函数原形: int pthread_attr_getinheritsched(const pthread_attr_t\attr,int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr,intinheritsched);*
参数: attr 线程属性变量inheritsched 线程的继承性
返回值: 若成功返回0,若失败返回-1

这两个函数具有两个参数,第1个是指向属性对象的指针,第2个是继承性或指向继承性的指针。继承性决定调度的参数是从创建的进程中继承还是使用在schedpolicyschedparam属性中显式设置的调度信息。Pthreads不为inheritsched指定默认值,因此如果你关心线程的调度策略和参数,必须先设置该属性。

​ 继承性的可能值是PTHREAD_INHERIT_SCHED(表示新现成将继承创建线程的调度策略和参数)和PTHREAD_EXPLICIT_SCHED(表示使用在schedpolicyschedparam属性中显式设置的调度策略和参数)。

​ 如果你需要显式的设置一个线程的调度策略或参数,那么你必须在设置之前将inheritsched属性设置为PTHREAD_EXPLICIT_SCHED.

​ 下面我来讲进程的调度策略和调度参数。我会结合下面的函数给出本函数的程序例子。

四、线程的调度策略

函数pthread_attr_setschedpolicypthread_attr_getschedpolicy分别用来设置和得到线程的调度策略。

4.

名称: pthread_attr_getschedpolicy**pthread_attr_setschedpolicy
功能: 获得/设置线程的调度策略
头文件: #include<pthread.h>
函数原形: int pthread_attr_getschedpolicy(const pthread_attr_t\attr,int *policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr,intpolicy);*
参数: attr 线程属性变量policy 调度策略
返回值: 若成功返回0,若失败返回-1

这两个函数具有两个参数,第1个参数是指向属性对象的指针,第2个参数是调度策略或指向调度策略的指针。调度策略可能的值是先进先出(SCHED_FIFO)、轮转法(SCHED_RR,或其它(SCHED_OTHER)。

SCHED_FIFO策略允许一个线程运行直到有更高优先级的线程准备好,或者直到它自愿阻塞自己。在SCHED_FIFO调度策略下,当有一个线程准备好时,除非有平等或更高优先级的线程已经在运行,否则它会很快开始执行。

SCHED_RR(轮循)策略是基本相同的,不同之处在于:如果有一个SCHED_RR

策略的线程执行了超过一个固定的时期(时间片间隔)没有阻塞,而另外的SCHED_RRSCHBD_FIPO策略的相同优先级的线程准备好时,运行的线程将被抢占以便准备好的线程可以执行。

​ 当有SCHED_FIFOSCHED_RR策赂的线程在一个条件变量上等持或等持加锁同一个互斥量时,它们将以优先级顺序被唤醒。即,如果一个低优先级的SCHED_FIFO线程和一个高优先织的SCHED_FIFO线程都在等待锁相同的互斥且,则当互斥量被解锁时,高优先级线程将总是被首先解除阻塞。

五、线程的调度参数(优先级)

​ 函数pthread_attr_getschedparampthread_attr_setschedparam分别用来设置和得到线程的调度参数。

5.

名称: pthread_attr_getschedparam**pthread_attr_setschedparam
功能: 获得/设置线程的调度参数
头文件: #include<pthread.h>
函数原形: int pthread_attr_getschedparam(const pthread_attr_t\attr,struct sched_param *param);
int pthread_attr_setschedparam(pthread_attr_t *attr,conststruct sched_param *param);*
参数: attr 线程属性变量param sched_param结构
返回值: 若成功返回0,若失败返回-1

这两个函数具有两个参数,第1个参数是指向属性对象的指针,第2个参数是sched_param结构或指向该结构的指针。结构sched_param在文件/usr/include/bits/sched.h中定义如下:​

struct sched_param

{

intsched_priority;

};

结构sched_param的子成员sched_priority控制一个优先权值,大的优先权值对应高的优先权。系统支持的最大和最小优先权值可以用sched_get_priority_max函数和sched_get_priority_min函数分别得到。

注意:如果不是编写实时程序,不建议修改线程的优先级。因为,调度策略是一件非常复杂的事情,如果不正确使用会导致程序错误,从而导致死锁等问题。如:在多线程应用程序中为线程设置不同的优先级别,有可能因为共享资源而导致优先级倒置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct sched_param	params;
/* first get the scheduling parameter, then set the new priority */
//设置线程的优先级
rval = pthread_attr_getschedparam(attr, &params);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}

rval = pthreadGetPriorityScope(&minPriority, &maxPriority);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}
if (priority < minPriority)
{
priority = minPriority;
}
else if (priority > maxPriority)
{
priority = maxPriority;
}
params.sched_priority = priority;
rval = pthread_attr_setschedparam(attr, &params);

六、线程的竞争范围

int pthread_attr_getscope(const pthread_attr_t *restrict attr,

int *restrict contentionscope);

int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);

定义创建的线程的竞争范围为PTHREAD_SCOPE_SYSTEM、PTHREAD_SCOPE_PROCESS。

Linux Threads只实现了PTHREAD_SCOPE_SYSTEM,这意味着,它将和机器上运行的所有进程竞争CPU时间。

标准指定的另外一个值,PTHREAD_SCOPE_PROCESS,表示竞争只存在于运行中的进程的线程之间:即,线程的优先级是相对于其它进程中的线程的优先级的,而不必考虑进程的优先级如何。LinuxThread不支持PTHREAD_SCOPE_PROCESS。

若成功返回0,若失败返回-1。

七、线程的栈的地址和大小

(1)

int pthread_attr_getstack(pthread_attr_t attr,void **stackaddr,size_tstacksize);

int pthread_attr_setstack(pthread_attr_t attr, void stackaddr,size_t stacksize);

设置线程栈的起始地址和栈大小。默认起始地址0,大小0x800000(8M,我的机子……)。

PS:使用get时往往显示的是addr = 0,size = 0,这可能是系统的BUG,size应给为8M而不是0。

(2)

上面的2个函数可以细化成4个:

int pthread_attr_setstackaddr(pthread_attr_t attr, void stackaddr);

int pthread_attr_getstackaddr(pthread_attr_t *attr, void**stackaddr);

int pthread_attr_setstacksize(pthread_attr_t *attr, size_tstacksize);

int pthread_attr_getstacksize(pthread_attr_t attr, size_tstacksize);

这里get得到的size为8M,所以pthread_attr_getstack获得的size大小是不能说明栈的大小的。

八、栈溢出保护区大小

intpthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

intpthread_attr_getguardsize(pthread_attr_t attr, size_t guardsize);

设置线程的栈溢出保护区大小,默认4096B,即4K。

九、设置/获取线程属性对象里CPU 姻亲属性

int pthread_attr_setaffinity_np(pthread_attr_t *attr,size_tcpusetsize,

const cpu_set_t *cpuset);

int pthread_attr_getaffinity_np(pthread_attr_t *attr, size_tcpusetsize,

cpu_set_t *cpuset);

函数把 attr 引用的线程属性对象中的 CPU 姻亲掩码设置为cpuset 指定的值。这个属性决定了使用线程属性对象 attr 创建的线程的 CPU 姻亲掩码。

十、获取实时优先级的最大最小值

Synopsis

#include <sched.h>

int sched_get_priority_max(int policy**);int sched_get_priority_min(int policy);**

Description

The sched_get_priority_max() and sched_get_priority_min() functions shall return the appropriate maximum or minimum, respectively, for the scheduling policy specified bypolicy.

The value of policy shall be one of the scheduling policy values defined in <sched.h>.

Return Value

If successful, the sched_get_priority_max() and sched_get_priority_min() functions shall return the appropriate maximum or minimum values, respectively. If unsuccessful, they shall return a value of -1 and set errno to indicate the error.

Errors

The sched_get_priority_max() and sched_get_priority_min() functions shall fail if:

  • EINVAL

    The value of the policy parameter does not represent a defined scheduling policy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
* Function: setPthreadAttr
* Description: set the pthread's attribute: priority and the stack size in details
* Input: priority - [minPriority, maxPriority]
* stacksize - the pthread's stack size
* Output: attr - the pthread's attribute
* Return: 0 if successful, otherwise return -1
*
*/
static int setPthreadAttr(pthread_attr_t *attr, int priority, size_t* stacksize)
{
int rval;
struct sched_param params;
int maxPriority, minPriority;

rval = pthread_attr_init(attr);
if (rval != 0)
{
return rval;
}

/* normally, need not to set */
#if 0
rval = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}

rval = pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM);
if (rval != 0)
{
if (rval == ENOTSUP)
{
PRINT("The system does not support the %s scope, using %s\n",
"PTHREAD_SCOPE_SYSTEM", "PTHREAD_SCOPE_PROCESS");

rval = pthread_attr_setscope(attr, PTHREAD_SCOPE_PROCESS);
}

if (rval)
{
pthread_attr_destroy(attr);
return rval;
}
}
#endif

/* use the round robin scheduling algorithm */
//设置线程调度模式,循环
rval = pthread_attr_setschedpolicy(attr, SCHED_RR);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}

/* set the thread to be detached */
//设置为分离线程,让线程结束的话释放自己的资源
rval = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}

/* first get the scheduling parameter, then set the new priority */
//设置线程的优先级
rval = pthread_attr_getschedparam(attr, &params);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}

rval = pthreadGetPriorityScope(&minPriority, &maxPriority);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}
if (priority < minPriority)
{
priority = minPriority;
}
else if (priority > maxPriority)
{
priority = maxPriority;
}
params.sched_priority = priority;
rval = pthread_attr_setschedparam(attr, &params);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}

/* when set stack size, we define a minmum value to avoid fail */
//设置栈大小,最小8192
if (*stacksize < PTHREAD_STACK_MIN)
{
*stacksize = PTHREAD_STACK_MIN;
}
rval = pthread_attr_setstacksize(attr, *stacksize);
if (rval != 0)
{
pthread_attr_destroy(attr);
return rval;
}
return 0;
}

/*
* Function: pthreadSpawn
* Description: create a pthread, this is a variadic function
* Input: priority - [minPriority, maxPriority]
* stacksize - new thread's stack size(byte)
* funcptr - function addr to start the new thread
* args - total optional arguments pass to the above function
* ... - optional arguments
* Output: ptid - pthread id
* Return: 0 if successful, otherwise an error number returned
*
*/
int pthreadSpawn(pthread_t *ptid, int priority, size_t stacksize,
void *(*funcptr)(void*, void*, void*, void*, void*, void*, void*, void*, void*, void*),
unsigned args, ...)
{
if (funcptr == NULL || args > 10)
{
return EINVAL;
}

int i, rval;
void *arg[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
START_ROUTINE start;
pthread_t tid, *raw;
pthread_attr_t attr;
va_list ap;
size_t actStackSize = stacksize;

va_start(ap, args);
for (i = 0; i < args; i++)
{
arg[i] = va_arg(ap, void *);
PRINTA("pthreadSpawn: arg[%d] = %d\n", i, (int)arg[i]);
}
va_end(ap);
rval = setPthreadAttr(&attr, priority, &actStackSize);
if (rval != 0)
{
PRINTA("setPthreadAttr failed %d,sys errno %d\n",rval,errno);
return rval;
}

if (ptid != NULL)
{
raw = ptid;
}
else
{
raw = &tid;
}
/*
* If the total optional argumens is 0 or 1, we call the pthread_create directly.
* Otherwise, we wrap a start routine.
*/
if (args <= 1)
{
rval = pthread_create(raw, &attr, (START_ROUTINE)funcptr, arg[0]);
}
else
{
FUNC_WRAPPER2 *func;
func = (FUNC_WRAPPER2 *)malloc(sizeof(FUNC_WRAPPER2));
if (func == NULL)
{
(void) pthread_attr_destroy(&attr);
return ENOMEM;
}
start = threadWrapper2;
memset((char *)func, 0, sizeof(FUNC_WRAPPER2));
func->entry = funcptr;
for (i = 0; i < args; i++)
{
func->arg[i] = arg[i];
}
rval = pthread_create(raw, &attr, start, (void *)func);
if (rval != 0)
{
free((char *)func);
}
}
pthread_attr_destroy(&attr);
PRINTA("pthread create: tid = %d, priority = %d, stacksize = %d\n", (int)*raw, priority, actStackSize);

return rval;
}

原文2:https://blog.csdn.net/Gpengtao/article/details/7792860

原文1:https://blog.csdn.net/pbymw8iwm/article/details/6721038