这篇博客主要介绍了线程相关的一些属性
线程有关的属性
POSIX.1中规定的线程属性有4个:detachstate、guardsize、stackaddr、stacksize
- detachstate
线程detach状态指的是:当我们不需要知道线程退出时的终止状态,可以设置线程为detach
状态,这样当线程退出时,它的资源会自动被系统回收。
在pthread中,以设置deatchstate为例,一般的过程大致如下:
#include <pthread.h>
int
makethread(void *(*fn)(void *), void *arg)
{
int err;
pthread tid;
pthread_attr_t attr;
//init attribute structure
err = pthread_attr_init(&attr);
if (err != 0)
return err;
//set detachstate attribute
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (err == 0)
err = pthread_create(&tid, &attr, fn, arg);
//destroy attribute structure
pthread_attr_destroy(&attr);
return err;
}
如代码所示,首先需要调用pthread_attr_init
初始化线程属性,然后调用专门设置
detachstate的方法pthread_attr_setdetachstate
设置属性值,最后需要调用
pthread_attr_destroy
释放线程属性。
pthread中设置属性大致都是这样的步骤,比较麻烦,但这是为了代码可移植性,各个操作
系统在保持函数签名一直下,各自实现自己的线程属性。
- stackaddr和stacksize
这几个变量都是控制线程栈大小的变量,因为实际中存在我们希望栈尽可能小一点和栈尽可
能大一些的情况。
- 希望栈小一些:因为一个进程内的所有线程公用一个地址空间,所以减少栈空间后才能容
纳更多的线程 - 希望栈大一些:栈上存储的时函数调用信息和函数内的自动变量,当函数调用层级很多时
,需要的函数调用信息会增大,就需要栈空间大。
我们就可以通过stacaddr和stacksize来设置栈大小
- guardsize
这个属性控制栈的末尾预留的安全空间的大小,安全空间能够防止栈溢出
mutex的属性
- process-shared
用途是控制mutex变量是否是多个线程共享的 - robust
当mutext被多个进程共享时,可能发生的情况是一个持有mutex的进程因为某种原因终止了
而且该进程终止前未释放mutex。这样可能导致其他进程等待获取mutex的进程处于永远等待
状态。
robust属性是应对这种情况的,当robust属性值设置为PTHREAD_MUTEX_ROBUST
时,其他进
程可以获取mutex,不需要处于永远等待的情况。 - type
mutex的类型,有如下类型:
-
PTHREAD_MUTEX_NORMAL
: 标准的锁类型,不检查任何错误或者死锁 -
PTHREAD_MUTEX_ERRORCHECK
: 会检查错误 -
PTHREAD_MUTEX_RECURSIVE
: 允许同一个线程多次获取锁,而不会报错 -
PTHREAD_MUTEX_DEFAULT
: 规定mutex创建时,默认mutex的类型,这个默认类型是上述
三种类型中的一种
其他类型锁的属性如下
名称 | 属性 |
---|---|
read-writer锁 | process-shared |
Condition变量 | process-shared,clock |
Barrier | process-shared |
condition变量用在等待某一条件发生,发生后唤醒当前线程,有的情况,可以传一个参数
设置最大等待时间,clock属性就是设置这个等待时间所用的时钟
可重入性(Reentrancy)
如果一个函数可以安全地被多个线程同时调用,那么这个函数就是线程安全或者可重入的
线程私有数据
同一个线程下的多个线程间资源都是共享的,不过某些场景下我们希望线程拥有私有的数据
这个也是支持的
cancel选项
一个线程可以调用pthread_cancel
函数向另外一个线程发出终止运行请求,与此相关的属
性有state和type
state:可以控制是否接受其他线程的终止请求
type:可以控制响应终止请求的时机:马上响应或者特定的函数调用处
线程和信号
信号发送至线程的,因此线程的信号也是公共资源,一般只有一个线程会响应信号
线程和fork
fork函数会创建一个子进程,子进程完全复制父进程。当在一个线程中调用fork时,这些依
然成立,但子进程只会有保留一个线程,就是调用fork的那个线程
但如果父进程中的其他线程持有锁,在子进程中,这个锁仍然是被持有的状态。