多线程编程-线程管理
4, 线程管理
4.1 设置线程属性
(1), 线程有以下几个属性需要设置:
1)线程是否自动分离或可以联合
2)线程私有栈的大小
3)线程栈的起始地址
4)线程的调度策略
(2), 设置线程属性的步骤:
1) 定义一个pthread_attr_t 变量。
2) 调用pthread_attr_init() 初始化该变量。
3) 在创建线程的函数中设置该变量的属性值。
4) 在创建线程pthread_create时的第2个参数,填写该变量的地址。
代码:
---------设置属性代码--------------
pthread_attr_t attr;
pthread_attr_init(&attr);
...
//set attr
...
pthread_create(NULL, &attr, thread_fun, NULL);
...
pthread_destory(&attr);
---------end--------------
(3), 设置线程的栈大小
a 线程使用它的私有栈来存储本地变量和它调用的每个函数的上下文。
b 两个关键因素决定了一个线程的栈空间是否足够:
一,是本地变量的大小
二,是该线程调用函数的多少
c 线程的私有栈一般比较小,具体多少由不同的平台决定,所有有时需要扩展线程私有栈的大小。
d 注意:线程栈的属性是线程的固有属性,不同的平台效果是不同的,因而该属性不可移植。
---------设置线程栈大小的例子--------------
/*
* example : change thread default stack size
*/
#include
#include
#include
//#define MIN_REQ_SIZE 81920
//10M+1k
#define MIN_REQ_SIZE 10486784
static size_t default_custom_size;
static pthread_attr_t stack_size_custom_attr;
void th_fun1(void)
{
pthread_attr_getstacksize(&stack_size_custom_attr, &default_custom_size);
fprintf(stderr, "default stack size1=[%d]\n", default_custom_size);
if (default_custom_size < MIN_REQ_SIZE) {
fprintf(stderr, "set stack size now...\n");
pthread_attr_setstacksize(&stack_size_custom_attr, MIN_REQ_SIZE);
}
pthread_attr_getstacksize(&stack_size_custom_attr, &default_custom_size);
fprintf(stderr, "default stack size2=[%d]\n", default_custom_size);
}
int
main(void)
{
pthread_t tid;
pthread_attr_init(&stack_size_custom_attr);
pthread_create(&tid, &stack_size_custom_attr, (void *)th_fun1, (void *)NULL);
pthread_attr_destory(&stack_size_custom_attr);
pthread_join(tid, NULL);
return 0;
}
----------------end---------------------------
问题:若使用的栈的大小超过了线程栈默认的栈的大小会怎样?会报什么错误?
(4), 设置线程的分离属性
a 若一个线程设置了分离属性,就不能使用pthread_join函数来获取该线程的退出状态
b 若一个线程的属性是分离的,退出时自动释放占用的系统资源,不需要使用pthread_join函数来释放。
----------------设置分离属性---------------------------
#include "../mtp_all.h"
static pthread_attr_t detach_attr;
void th_fun(void)
{
int i;
int now_attr_detached;
for (i=0; i<100000; i++)
;
// get now attr
pthread_attr_getdetachstate(&detach_attr, &now_attr_detached);
fprintf(stderr, "now stat2: %s\n", (now_attr_detached==PTHREAD_CREATE_DETACHED)?"detached":"tached");
}
int
main(void)
{
pthread_t tid;
int st;
pthread_attr_init(&detach_attr);
// get now attr
pthread_attr_getdetachstate(&detach_attr, &st);
fprintf(stderr, "now stat1: %s\n", (st==PTHREAD_CREATE_DETACHED)?"detached":"tached");
//init detached attribute to detached.
pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &detach_attr, (void *)th_fun, (void *)NULL);
//为了成功创建出新的线程,这里睡眠2秒,是一个权益之计,但不是最好的方法
sleep(2);
pthread_attr_destory(&detach_attr);
pthread_exit(NULL);
}
----------------end---------------------------
(5) 设置多重属性值
a 可以为一个属性变量设置多种属性值
----------------设置多重属性---------------------------
pthread_attr_t custom_attr;
.
pthread_attr_init(&custom_attr);
.
pthread_attr_setstacksize(&custom_attr, MIN_REQ_SSIZE);
pthread_attr_setdetachedstate(&custom_attr, PTHREAD_CREATE_DETACHED);
.
.
pthread_create(&thread, &custom_attr, ...);
.
//这里销毁属性变量对创建的新的线程没有影响。
pthread_attr_destory(&custom_attr);
----------------end---------------------------
4.2 最多初始化一次
有时在创建多线程时可能会用到初始化函数来对变量进行动态初始化。但有的变量只能初始化一次,
多次初始化的后果是无法预知的。这时就要用到pthread_once函数。
----------------只初始化一次---------------------------
#include
#include
static pthread_once_t t_once=PTHREAD_ONCE_INIT;
pthread_mutex_t mutex;
void init_pthread(void)
{
static int n = 0;
pthread_mutex_init(&mutex, NULL);
n++;
fprintf(stderr, "n=[%d]\n", n);
}
int main(void)
{
int ret;
/* just run init function once */
ret = pthread_once(&t_once, init_pthread);
fprintf(stderr, "ret=[%d]\n", ret);
// 第二次调用时,init_pthread将不会被执行:
// ret仍然返回0,但不会执行打印语句。
ret = pthread_once(&t_once, init_pthread);
fprintf(stderr, "ret=[%d]\n", ret);
return 0;
}
----------------end---------------------------
总结: 在对互斥变量、条件变量、或其他需要只初始化一次的变量进行初始化时,使用pthread_once进行。