线程属性为一个结构体:
typedef struct { int detachstate; //线程的分离状态 int schedpolicy; //线程调度策略 structsched_param schedparam; //线程的调度參数 int inheritsched; //线程的继承性 int scope; //线程的作用域 size_t guardsize; //线程栈末尾的警戒缓冲区大小 void* stackaddr; //线程栈的位置 size_t stacksize; //线程栈的大小 }pthread_attr_t;
一、线程分离状态:detachstate
该属性决定了线程运行任务后以什么方式来结束自己。
(1) PTHREAD_CREATE_DETACHED —— 分离线程
置为分离线程的线程。当不须要被不论什么线程等待,线程运行完任务后,自己自己主动结束线程,并释放资源。
(2) PTHREAD_CREATE_JOINABLE(缺省) —— 可汇合线程
可汇合线程为线程的默认状态,这样的情况下,原有的线程等待创建的线程结束。仅仅有当pthread_join()函数返回时。创建的线程才算终止。才干释放自己占用的系统资源。
使用方法:
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
注意:
pthread_exit只用来退出线程,不会释放线程资源。只有在pthread_create后加上pthread_join函数调用才会释放资源。只要有了pthread_join,即使没有调用pthread_exit,线程退出时也会释放内存。
也就是说pthread_exit只是线程的一个出口,和资源的释放无关,pthread_join直接决定资源是否能够及时释放。举个例子:
void *run(void*p) { pthread_exit(0); //可以不要,会自动调用 } int main () { pthread_t tid; int rc; long count = 0; while(1) { if((rc=pthread_create(&tid, NULL, run,NULL))!=0) { printf("ERROR, rc is %d, %ld threads create fail\n", rc, count); perror("Fail:"); return -1; } //pthread_join(thread,0); if(count++%100==0) printf("%ld threads created\n", count); } return 0; }
把pthread_join(thread,0)注释拿掉,发现无论创建多少个线程都不会再出错了,说明创建的线程资源退出时得到了释放。
int rc, state; pthread_attr_getdetachstate(&attr, &state); if(PTHREAD_CREATE_JOINABLE == state) printf("pthread_attr_getdetachstate: PTHREAD_CREATE_JOINABLE\n"); else if(PTHREAD_CREATE_DETACHED == state) printf("pthread_attr_getdetachstate: PTHREAD_CREATE_DETACHED\n"); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
同理,那么将线程设置成分离线程,发现无论创建多少个线程都不会再出错了,说明创建的线程资源退出时得到了释放。
void *run(void*p) { pthread_exit(0); //可以不要,会自动调用 } int main () { pthread_t tid; int rc; long count = 0; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); while(1) { if((rc=pthread_create(&tid, &attr, run,NULL))!=0) { printf("ERROR, rc is %d, %ld threads create fail\n", rc, count); perror("Fail:"); return -1; } //pthread_join(thread,0); if(count++%100==0) printf("%ld threads created\n", count); } return 0; }
二、线程的调度策略:schedpolicy
内核默认调度算法是循环时间分享策略(SCHED_OTHER或SCHED_NORMAL)。
实时调度策略分为两种SCHED_RR和SCHED_FIFO,linux系统中,这两个调度策略都有99个优先级,其优先级数值从1(低优先级)~ 99(高优先级),每个优先级又有一个队列。
(1) SCHED_FIFO(先进先出策略)
同优先级的实时进程,后进入的进程要等前一个进程释放了CPU,才能够运行。(没有时间片)
不同优先级的实时进程,高优先级的实时进程能够抢占低优先级的实时进程。
(2) SCHED_RR(轮转策略)
同优先级的实时进程中,每个进程又是通过获得时间片来分时运行。
不同优先级的实时进程,高优先级的实时进程能够抢占低优先级的实时进程。
(3) SCHED_OTHER(循环时间分享策略)
一般线程默认是SCHED_OTHER,这种调度策略没有优先级。所有task排队分享时间片,可以用pthread_attr_getschedpolicy,pthread_attr_setschedpolicy获取和设置调度策略。
pthread_attr_t attr; int policy; pthread_attr_init(&attr); pthread_attr_getschedpolicy(&attr, &policy); if (policy == SCHED_FIFO) printf("SCHED_FIFO policy\n"); else if(policy == SCHED_RR) printf("SCHED_RR policy\n"); else if(policy == SCHED_OTHER) printf("SCHED_OTHER policy\n"); pthread_attr_setschedpolicy(&attr, SCHED_RR);
三、调度參数 : sched_param schedparam
这两个函数具有两个參数。第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函数分别得到。
struct sched_param param; ret = pthread_attr_getschedparam(&attr, ¶m); param.sched_priority = 85; pthread_attr_setschedparam( &attr, ¶m);
注意:假设不是编写实时程序,不建议改动线程的优先级。由于,调度策略是一件很复杂的事情,假设不对使用会导致程序错误,从而导致死锁等问题。
如:在多线程应用程序中为线程设置不同的优先级别,有可能由于共享资源而导致优先级倒置。
四、线程的继承性: inheritsched
(1) PTHREAD_INHERIT_SCHED(缺省) —— 调度属性自创建者线程继承
(2) PTHREAD_EXPLICIT_SCHED —— 调度属性由调度參数和调度策略决定
继承性决定调度的參数是从创建的进程中继承还是使用在schedpolicy和schedparam属性中显式设置的调度信息。Pthreads不为inheritsched指定默认值,因此假设你关心线程的调度策略和參数,必须先设置该属性。
pthread_attr_getinheritsched(&attr, &schedinherited); if(PTHREAD_INHERIT_SCHED == schedinherited) printf("pthread_attr_getinheritsched: PTHREAD_INHERIT_SCHED\n"); else if(PTHREAD_EXPLICIT_SCHED == schedinherited) printf("pthread_attr_getinheritsched: PTHREAD_EXPLICIT_SCHED\n"); pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
五、线程的作用域:scope
线程的竞争范围。
PTHREAD_SCOPE_SYSTEM ——在系统范围内竞争资源。
PTHREAD_SCOPE_PROCESS(Linux不支持)——在进程范围内竞争资源
pthread_attr_getscope(&attr, &scope); if(PTHREAD_SCOPE_PROCESS == scope) printf("pthread_attr_getscope: PTHREAD_SCOPE_PROCESS\n"); else if(PTHREAD_SCOPE_SYSTEM == scope) printf("pthread_attr_getscope: PTHREAD_SCOPE_SYSTEM\n");
六、线程栈末尾的警戒缓冲区大小:guardsize
该属指定线程末尾的警戒缓冲区大小,在缺省的情况下为一个内存页(4096字节)
ret = pthread_attr_getguardsize(&attr, &size); if(0 != ret) { ERROR("pthread_attr_getguardsize", ret); } else { printf("pthread_attr_getguardsize: %lu\n", size); }
七、线程栈的位置:stackaddr
void* stackaddr = malloc(PTHREAD_STACK_MIN); pthread_attr_getstackaddr(&attr, &stackaddr);
八、线程栈的大小:stacksize
size_t size; ret = pthread_attr_getstacksize(&attr, &size); if(0 != ret) { ERROR("pthread_attr_getstacksize", ret); } else { printf("pthread_attr_getstacksize: %lu\n", size); } pthread_attr_destroy(&attr);
九、线程id
pthread_self()
十、 pthread_once一次性初始化
1.传统静态变量控制
在传统的顺序编程中,一次性初始化经常通过使用静态变量来控制。
void func() { Static flag =1; While(flag) Do_once_init(); Flag=0; }
这里循环调用func时,由于静态变量flag的限制,只会调用一次Do_once_init()。
但是在多线程程序设计中,事情就变的复杂的多。如果多个线程并发地执行func,那么每个线程进入。
void do_once_init() { puts("do once init."); } void func(void) { static int flag = 1; if (flag) { do_once_init(); Flag = 0; } } static void *thread1(void *data){func();pthread_exit(NULL);} static void *thread2(void *data){func();pthread_exit(NULL);} static void *thread3(void *data){func();pthread_exit(NULL);} int main() { pthread_t tid1,tid2, tid3; void*status=NULL; pthread_create(&tid1, NULL, thread1, NULL); pthread_create(&tid2, NULL, thread2, NULL); pthread_create(&tid3, NULL, thread3, NULL); pthread_join(tid1,&status); pthread_join(tid2,&status); pthread_join(tid3,&status); return 0; }
可以看到3个thread同时执行了.
如果多个线程并发地执行初始化序列代码,而我们希望该过程本该仅仅执行一次。
2.一次性初始化
如果我们需要对一个posix变量静态的初始化,可使用的方法是用一个互斥量对该变量的初始化进行控制。但有时候我们需要对该变量进行动态初始化,pthread_once就会方便的多。
static pthread_once_t once = PTHREAD_ONCE_INIT; void do_once_init() { puts("do once init."); } void func(void) { do_once_init(); } static void *thread1(void *data){pthread_once(&once, func);pthread_exit(NULL);} static void *thread2(void *data){pthread_once(&once, func);pthread_exit(NULL);} static void *thread3(void *data){pthread_once(&once, func);pthread_exit(NULL);} int main() { pthread_t tid1,tid2, tid3; void*status=NULL; pthread_create(&tid1, NULL, thread1, NULL); pthread_create(&tid2, NULL, thread2, NULL); pthread_create(&tid3, NULL, thread3, NULL); pthread_join(tid1,&status); pthread_join(tid2,&status); pthread_join(tid3,&status); return 0; }