关于线程分离状态

来源:互联网 发布:矩阵卷积运算 编辑:程序博客网 时间:2024/05/22 06:17


一:设置分离状态:
线程的分离状态:PTHREAD_CREATE_JOINABLE(非分离状态),需要pthread_join释放thread资源, PTHREAD_CREATE_DETACHED(分离状态),线程结束后自动回收资源。
int pthread_attr_getdetachstate(const pthread_attr_t *attr,int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
不管是分离状态还是非分离状态,在子thread全部退出之前退出主程序都是很有风险的。
如果主thread选择return或者exit()退出,则所有thread都会被kill掉,这样很容易出错。
如果主thread调用pthread_exit(),则仅主线程本身终止,进程及进程内的其他线程将继续存在,直到所有线程都终止时,进程才终止。


二:设置栈溢出保护区大小:
栈溢出概念:
    溢出保护可能会导致系统资源浪费。如果应用程序创建大量线程,并且已知这些线程永远不会溢出其栈,则可以关闭溢出保护区。通过关闭溢出保护区,可以节省系统资源。
    线程在栈上分配大型数据结构时,可能需要较大的溢出保护区来检测栈溢出。
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr,size_t guardsize);
设置和得到栈溢出保护区。如果guardsize设为0。则表示不设置栈溢出保护区。guardsize 的值向上舍入为 PAGESIZE 的倍数。


三:设置thread竞用范围:
竞用范围(PTHREAD_SCOPE_SYSTEM 或 PTHREAD_SCOPE_PROCESS)指 使用 PTHREAD_SCOPE_SYSTEM 时,此线程将与系统中的所有线程进行竞争。使用 PTHREAD_SCOPE_PROCESS 时,此线程将与进程中的其他线程进行竞争。
int pthread_attr_getscope(const pthread_attr_t *restrict attr,int *restrict contentionscope);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);


四:设置线程并行级别:
int pthread_getconcurrency(void);
int pthread_setconcurrency(int new_level); 


五:设置调度策略:
POSIX 标准指定 SCHED_FIFO(先入先出)、SCHED_RR(循环)或 SCHED_OTHER(实现定义的方法)的调度策略属性。
    SCHED_FIFO
    如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM) 的先入先出线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,则会继续处理该线程,直到该线程放弃或阻塞为止。对于具有进程争用范围 (PTHREAD_SCOPE_PROCESS)) 的线程或其调用进程没有有效用户 ID 0 的线程,请使用 SCHED_FIFO。SCHED_FIFO 基于 TS 调度类。
    SCHED_RR
    如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM)) 的循环线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,并且这些线程没有放弃或阻塞,则在系统确定的时间段内将一直执行这些线程。对于具有进程争用范围 (PTHREAD_SCOPE_PROCESS) 的线程,请使用 SCHED_RR(基于 TS 调度类)。此外,这些线程的调用进程没有有效的用户 ID 0。
SCHED_FIFO 是基于队列的调度程序,对于每个优先级都会使用不同的队列。SCHED_RR 与 FIFO 相似,不同的是前者的每个线程都有一个执行时间配额。
int pthread_attr_getschedpolicy(const pthread_attr_t *restrict attr,int *restrict policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);


六:设置优先级:
int pthread_attr_getschedparam(const pthread_attr_t *restrict attr,struct sched_param *restrict param);
int pthread_attr_setschedparam(pthread_attr_t *restrict attr, const struct sched_param *restrict param);


七:设置栈大小:
当创建一个thread时,会给它分配一个栈空间,线程栈是从页边界开始的。任何指定的大小都被向上舍入到下一个页边界。不具备访问权限的页将被附加到栈的溢出端(第二项设置中设置)。
指定栈时,还应使用 PTHREAD_CREATE_JOINABLE 创建线程。在该线程的 pthread_join() 调用返回之前,不会释放该栈。在该线程终止之前,不会释放该线程的栈。了解这类线程是否已终止的唯一可靠方式是使用 pthread_join。
一般情况下,不需要为线程分配栈空间。系统会为每个线程的栈分配指定大小的虚拟内存。
#ulimit -a可以看到这个缺省大小


1.创建thread.
int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);
参数1:pthread_t *restrict thread:创建thread的thread ID.
参数2:const pthread_attr_t *restrict attr:创建线程的属性。
参数3:void *(*start_routine)(void*):thread服务程序。
参数4:void *restrict arg:thread服务程序参数。


2. 等待目标线程终止:
pthread_join() 函数会一直阻塞调用线程,直到指定的线程终止。
指定的线程必须位于当前的进程中,而且不得是分离线程。所有创建时属性为PTHREAD_CREATE_JOINABLE的非分离thread. 最终都需要调用pthread_join() or pthread_detach() 。这样thread所占资源和 Thread ID 才被释放。


3. 分离thread:
int pthread_detach(pthread_t thread);
pthread_detach()指出当thread 结束时,thread所占资源和Thread ID会被释放和再利用。如果调用pthread_detach()时,thread没有结束,它并不会导致thread退出。它只对PTHREAD_CREATE_JOINABLE 非分离thread有效。


4. 获取thread ID:
pthread_t pthread_self(void);
返回调用thread的thread ID.


5. 比较thread ID:
int pthread_equal(pthread_t t1, pthread_t t2);如果 tid1 和 tid2 相等,pthread_equal() 将返回非零值,否则将返回零。


6. 向thread发信号:
int pthread_kill(pthread_t thread, int sig);
tid 所指定的线程必须与调用线程在同一个进程中。sig 参数必须来自 signal(5) 提供的列表。


7. 退出线程:
void pthread_exit(void *value_ptr);
pthread_exit()用来终止调用thread并置位value_ptr.这个值会交给pthread_join。


Thread的取消:
同一进程内,某个Thread可以向其它thread发送取消要求,要求目标thread退出运行。
取消请求的处理方式取决于目标线程的状态。状态由以下两个函数确定:pthread_setcancelstate() 和 pthread_setcanceltype()。
pthread_setcancelstate() 启用或禁用线程取消功能。创建线程时,缺省情况下线程取消功能处于启用状态。
pthread_setcanceltype() 可以将取消类型设置为延迟或异步模式。创建线程时,缺省情况下会将取消类型设置为延迟模式。在延迟模式下,只能在取消点取消线程。在异步模式下,可以在执行过程中的任意一点取消线程。因此建议不使用异步模式。
执行取消操作存在一定的危险。大多数危险都与完全恢复不变量和释放共享资源有关。取消线程时一定要格外小心,否则可能会使互斥保留为锁定状态,从而导致死锁。或者,已取消的线程可能保留已分配的内存区域,但是系统无法识别这一部分内存,从而无法释放它。
如果创建thread时使用缺省设置,则thread可以被取消,并为异步方式,所以向某一thread发送pthread_cancel()后,并不保证什么时候目标thread会被取消。只有当目标thread运行至取消点时才会真正退出。
类似Read,write等阻塞函数可以被看作取消点,但Sam记得并不能保证。所以建议使用手动添加取消点。


pthread_testcancel();
当线程取消功能处于启用状态且取消类型设置为延迟模式时,pthread_testcancel() 函数有效。如果在取消功能处于禁用状态下调用 pthread_testcancel(),则该函数不起作用。
请务必仅在线程取消操作安全的序列中插入 pthread_testcancel()。


误区1: 分离线程不能被cancel.
这是将pthread_join与pthread_cancel搞混了。
thread分离可以在创建时设定,也可以用pthread_detach()在创建后设定。
被设定成分离线程后,表明它在退出thread时会自动回收资源。所以不需要pthread_join. 但分离thread完全可以接收pthread_cancel()来退出。


误区2:已经退出的thread,再去对它pthread_cancel()会出错。
不会出错,如果某thread已经退出,再向它发送pthread_cancel().不会出错。但会返回ESRCH。此值为3。
ESRCH  No thread could be found corresponding to that specified by the given thread ID.
这里显示出:一个thread,不管自身return或pthread_exit(). 此thread都算停掉了。只是不分离thread需要使用pthread_join来回收资源而已。


注意1:不管是否分离,主thread先于其它thread退出,都是不可控的。也就是说会不可预知错误。所以,主thread不要使用return,exit等退出。 而是使用pthread_exit().
主thread使用pthread_exit(). 则会阻赛之,直到所有子thread退出后才退出。
原创粉丝点击