1. 线程限制
与其它的系统限制一样,这些线程限制也是通过sysconf函数进行查询的。当某些操作系统实现没有定义相应的sysconf符号(_SC_)时,表示为"未定义符号";如果操作系统实现的限制是不确定的,表示为"没有确定的限制",但这并不意味是无限制的;"不支持"表明操作系统实现定义了相应的sysconf限制符号,但是sysconf函数无法识别这个符号。
2. 线程属性
在调用pthread_create时,可以使用pthread_attr_init函数初始化pthread_attr_t 结构,就是支持操作系统所支持的线程所有默认属性。如果需要修改其中个别属性值,需要调用其它的函数。如果要去除pthread_attr_t结构的初始化,可以调用pthread_attr_destroy函数。如果pthread_attr_init实现时为属性对象分配了空间,pthread_attr_destroy将会释放该内存空间。pthread_attr_t结构对应用程序是不透明的,增强了程序可移植性。
int pthread_attr_init (pthread_attr_t *attr);
pthread_t phread_attr_destroy(pthread_attr_t *attr);
2.1. 分离线程
如果对现有的某个线程的终止状态不感兴趣,可以用pthread_detach函数让操作系统在线程退出时收回它所占有的资源。如果在创建线程时就知道不需要了解线程的终止状态,这可以修改pthread_attr_t结构中的detachstate线程属性,让线程以分离状态启动。detachstate线程属性有两个合法值:设置为PTHREAD_CREATE_DETACHED,以分离状态启动线程;或者设置为PTHREAD_CREATE_JOINABLE,正常启动线程,应用程序可以获取线程的终止状态。
int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr,
int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int *detachstate);
2.2. 线程栈属性(stacksize)
对于遵循XSI的系统,支持线程栈属性就是必须的。可以通过在运行阶段把_SC_THREAD_ATTR_STACKADDR和_SC_THREAD_ATTR_STACKSIZE参数传给sysconf函数,检查系统线程栈属性的支持情况。线程栈属性的查询和修改一般是通过较新的函数pthread_attr_getstack和pthread_attr_setstack来进行。
int pthread_attr_getstack (const pthread_attr_t *restrict attr,
void **restrict stackaddr,
size_t *restrict stacksize);
int pthread_attr_setstack (const thread_attr_t *attr,
void *stackaddr,size_t stacksize);
对于进程来说,虚拟地址空间的大小是固定的,进程中只有一个栈,所以它的大小通常不是问题。但是对于线程来说,同样大小的虚拟地址空间必须被所有的线程共享。如果应用程序使用太多的线程,至使线程栈的累计大小超过了可用的虚拟地址空间,这时就需要减少线程默认的栈大小;如果线程调用的函数分配了大量的自动变量或者调用的函数涉及很深的栈帧,则这时需要的栈大小可能比默认的大。
如果用完了线程栈的虚拟地址空间,可以使用malloc和mmap来为其他的线程分配空间,并用pthread_attr_getstack函数来改变新建立线程的栈位置。线程栈所占内存范围中可寻址的最低地址可以由stackaddr参数指定,该地址与处理器结构相应的边界对齐。
应用程序也可以设置或读取线程属性stacksize。
int pthread_attr_getstacksize (const pthread_attr_t *restrict attr,
size_t *restrict stacksize);
int pthread_attr_setstacksize (thread_attr_t *attr, size_t stacksize);
2.3. 线程属性(guardsize)
线程属性guardsize控制着线程栈末尾之后用以避免栈溢出的扩展内存的大小。这个属性默认为PAGESIZE个字节。如果把guardsize设置为0,操作系统就不会提供警戒缓冲区。
int pthread_attr_getguardsize (const pthread_attr_t *restrict attr,
size_t *restrict guardsize);
int pthread_attr_setguardsize (thread_attr_t *attr, size_t guardsize);
如果guardsize线程属性被修改了,操作系统可能把它取为页大小的整数倍。如果线程的栈指针溢出到警戒区域,应用程序就可能通过信号收到出错信息。
2.4. 并发度
并发度控制着用户级线程可以映射的内核线程或进程的数目。
int pthread_getconcurrency (void);
int pthread_setconcurrency (int level);
如果操作系统之前没有设置过并发度,函数pthread_getconcurrency将返回0。函数pthread_setconcurrency设定的并发度只是对系统的一个提示,系统并不保障请求的并发度一定被采用。
2.5. 可取消状态
有两个线程属性并没有包括在pthread_attr_t结构中,它们是可取消状态和可取消类型。这两个属性影响着线程在响应pthread_cancel函数调用时所呈现的行为。
可取消状态可以是PTHREAD_CANCEL_ENABLE,也可以是PTHREAD_CANCEL_DISABLE。线程可以通过调用pthread_setcancelstate修改它的可取消状态。
int pthread_setcancelstate(int state, int *oldstate);
函数pthread_cancel调用并不等待线程终止,在默认情况下,线程在取消请求发出以后还是继续运行,直到线程到达某个取消点。取消点是线程检查是否被取消并按照请求进行动作的一个位置。线程启动时默认的可取消状态是PTHREAD_CANCEL_ENABLE。当状态设置为PTHREAD_CANCEL_DISABLE,对pthread_cancel的调用并不会杀死线程;相反,取消请求对这个线程处于未决状态。当取消状态再次变为PTHREAD_CANCEL_ENABLE时,线程将在下一个取消点上对所有的取消请求进行处理。
如果应用程序在很长一段时间内都不会调用到有取消点的函数,那么可以调用pthread_testcancel函数在程序中自己添加取消点。
int pthread_testcancel(void);
调用pthread_testcancel时,如果在某个取消请求处于未决状态,而且取消并没有置为无效,那么线程就会被取消。但是如果取消被置为无效时,pthread_testcancel调用就没有任何效果。
2.6. 可取消类型
默认取消类型为延迟取消。调用pthread_cancel以后,在线程到达取消点之前,并不会出现真正的取消。可以通过pthread_setcanceltype来修改取消类型。
int pthread_setcanceltype(int type, int *oldtype);
type参数可以是PTHREAD_CANCEL_DEFERRED,也可以是PTHREAD_CANCEL_ASYSCHRONOUS。异步取消与延迟不同,使用异步取消时,线程可以再任意时间取消,而不是非得遇到取消点才能被取消。