- 浏览: 141197 次
文章分类
最新评论
在线程基础函数一节中我们曾提到在调用 pthread_create 函数时可以指定线程属性,还可以用 pthread_detach 函数来分离线程,以让操作系统在线程退出时收回它所占用的资源。现在就是深入讨论这个话题的时候。
可以使用 pthread_attr_t 结构修改线程默认属性,并把这些属性与创建的线程联系起来。
pthread_attr_init 函数可以用来初始化 pthread_attr_t 结构。调用该函数后,线程属性结构包含的就是操作系统支持的所有线程属性的默认值。pthread_attr_destroy 函数则可以释放动态分配的属性对象的内存空间,还会用无效的值初始化属性对象。
下表总结了 POSIX.1 定义的线程属性以及各个操作系统平台的支持情况。
如果在创建线程时就知道不需要了解线程的终止状态,就可以使用 pthread_attr_t 结构中的 detachstate 线程属性,让线程一开始就处于分离状态。pthread_attr_setdetachstate 函数可以把线程属性设置成以下两个合法值之一:PTHREAD_CREATE_DETACHED,以分离状态启动线程;或者 PTHREAD_CREATE_JOINABLE,正常启动线程,此时应用程序可以获取线程的终止状态。函数 pthread_attr_getdetachstate 则可用来获取当前的 detachstate 线程属性。
下面给出了一个以分离状态创建线程的函数。
注意,这里忽略了 pthread_attr_destroy 的返回值,以免覆盖 pthread_create 的返回值。因此万一该函数的清理工作失败,则可能会有少量的内存泄漏。
遵循 POSIX 标准的系统不一定支持线程栈属性,可以在编译阶段使用 _POSIX_THREAD_ATTR_STACKADDR 和 _POSIX_THREAD_ATTR_STACKSIZE 符号或者在运行阶段把 _SC_THREAD_ATTR_STACKADDR 和 _SC_THREAD_ATTR_STACKSIZE 参数传给 sysconf 函数来检查系统是否支持每一个线程栈属性。
下面是一组可用来操作线程栈属性的函数。
对于进程来说,虚地址空间的大小是固定的,因为进程中只有一个栈,所以它的大小通常不是问题。但对于线程来说,同样大小的虚地址空间必须被所有的线程栈共享。如果这些线程栈的累计大小超过了可用的虚地址空间,就需要减少默认的线程栈大小。而如果线程调用的函数分配了大量的自动变量,或者涉及许多很深的栈帧,那么所需的栈大小又可能要比默认的大。如果线程栈的虚地址空间都用完了,则可以使用 malloc 或 mmap 来为可替代的栈分配空间,并用 pthread_attr_setstack 函数来改变新建线程的栈位置。其中 stackaddr 参数指定的地址可以用作线程栈的内存范围中的最低可寻址地址(但不一定是栈的开始位置,因为如果栈是从高地址向低地址增长的,则 stackaddr 将是栈的结尾位置),该地址与处理器结构相应的边界应对齐(假设 malloc 和 mmap 所用的虚地址范围与线程栈当前使用的虚地址范围不同)。
pthread_attr_getstacksize 和 pthread_attr_setstacksize 函数可以读取和设置线程属性 stacksize。如果希望改变默认的栈大小,但又不想自己处理线程栈的分配问题,这时使用 pthread_attr_setstacksize 函数就很有用。不过设置 stacksize 属性时,选择的 stacksize 不能小于 PTHREAD_STACK_MIN。
线程属性 guardsize 控制着线程栈末尾之后用以避免栈溢出的扩展内存的大小。该属性默认值是由具体实现来定义的,但常用值是系统页大小。可以把 guardsize 属性设置为 0,这样就不会提供警戒缓冲区。如果修改了 stackaddr 属性,系统也会认为我们将自己管理栈,进而使警戒缓冲区机制无效。如果 guardsize 属性被修改了,操作系统可能会把它取为页大小的整数倍。如果线程的栈指针溢出到警戒区域,应用程序就可能通过信号接收到出错信息。
不过有两个线程属性并没有包含在 pthread_attr_t 结构中,它们是可取消状态和可取消类型。它们影响着线程在响应 pthread_cancel 函数调用时所呈现的行为。
可取消状态属性可以是 PTHREAD_CANCEL_ENABLE 或 PTHREAD_CANCEL_DISABLE。线程可以调用 pthread_setcancelstate 来修改它的可取消状态。
pthread_setcancelstate 把当前的可取消状态设置为 state,并把原来的可取消状态存储在 oldstate 指向的内存单元中,这两步是一个原子操作。
因为 pthread_cancel 不会等待线程终止,所以默认情况下,线程在取消请求发出后会继续运行,直到线程到达某个取消点。取消点是线程检查它是否被取消的一个位置,如果取消了,则按照请求行事。POSIX.1 保证取消点在线程调用下图中的任何函数时都会出现。
线程默认是可取消的,当可取消状态设为 PTHREAD_CANCEL_DISABLE 时,调用 pthread_cancel 并不会杀死线程。相反,取消请求对这个线程来说还处于挂起状态。当取消状态再次变为 PTHREAD_CANCEL_ENABLE 时,线程将在下一个取消点上对所有挂起的取消请求进行处理。
除了上图中的函数,POSIX.1 还指定了下图中的函数作为可选的取消点。
如果应用程序在很长的一段时间内都不会调用上面两个图中的函数,也可以调用 pthread_testcancel 函数在程序中添加自己的取消点。调用该函数时,如果有某个取消请求正处于挂起状态,而且取消并没有置为无效,那么线程就会被取消,否则将不会有任何效果。
上面描述的默认的取消类型也称为推迟取消,调用 pthread_cancel 后,在线程到达取消点之前,并不会出现真正的取消。可以通过 pthread_setcanceltype 来修改取消类型。
type 参数可以是 PTHREAD_CANCEL_DEFERRED 或 PTHREAD_CANCEL_ASYNCHRONOUS,该函数把取消类型设置为 type,并把原来的取消类型保存到 oldtype 指向的内存单元中。使用异步取消时,线程就可以在任意时间撤销了。
可以使用 pthread_attr_t 结构修改线程默认属性,并把这些属性与创建的线程联系起来。
#include <pthread.h> int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr); /* 两个函数的返回值:若成功,返回 0;否则,返回错误编号 */
pthread_attr_init 函数可以用来初始化 pthread_attr_t 结构。调用该函数后,线程属性结构包含的就是操作系统支持的所有线程属性的默认值。pthread_attr_destroy 函数则可以释放动态分配的属性对象的内存空间,还会用无效的值初始化属性对象。
下表总结了 POSIX.1 定义的线程属性以及各个操作系统平台的支持情况。
如果在创建线程时就知道不需要了解线程的终止状态,就可以使用 pthread_attr_t 结构中的 detachstate 线程属性,让线程一开始就处于分离状态。pthread_attr_setdetachstate 函数可以把线程属性设置成以下两个合法值之一:PTHREAD_CREATE_DETACHED,以分离状态启动线程;或者 PTHREAD_CREATE_JOINABLE,正常启动线程,此时应用程序可以获取线程的终止状态。函数 pthread_attr_getdetachstate 则可用来获取当前的 detachstate 线程属性。
#include <pthread.h> int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr, int *detachstate); int pthread_attr_setdetachstate(pthread_attr_t *attr, int *detachstate); /* 两个函数的返回值:若成功,返回 0;否则,返回错误编号 */
下面给出了一个以分离状态创建线程的函数。
#include <pthread.h> int makeDetachThread(void *(*fn)(void *), void *arg){ pthread_t tid; pthread_attr_t attr; int err = pthread_attr_init(&attr); if(err != 0) return err; err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if(err == 0) err = pthread_create(&tid, &attr, fn, arg); pthread_attr_destroy(&attr); return err; }
注意,这里忽略了 pthread_attr_destroy 的返回值,以免覆盖 pthread_create 的返回值。因此万一该函数的清理工作失败,则可能会有少量的内存泄漏。
遵循 POSIX 标准的系统不一定支持线程栈属性,可以在编译阶段使用 _POSIX_THREAD_ATTR_STACKADDR 和 _POSIX_THREAD_ATTR_STACKSIZE 符号或者在运行阶段把 _SC_THREAD_ATTR_STACKADDR 和 _SC_THREAD_ATTR_STACKSIZE 参数传给 sysconf 函数来检查系统是否支持每一个线程栈属性。
下面是一组可用来操作线程栈属性的函数。
#include <pthread.h> int pthread_attr_getstack(const pthread_attr_t *restrict attr, void **restrict stackaddr, size_t *restrict stacksize); int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize); int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); 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); /* 所有函数的返回值:若成功,返回 0;否则,返回错误编号 */
对于进程来说,虚地址空间的大小是固定的,因为进程中只有一个栈,所以它的大小通常不是问题。但对于线程来说,同样大小的虚地址空间必须被所有的线程栈共享。如果这些线程栈的累计大小超过了可用的虚地址空间,就需要减少默认的线程栈大小。而如果线程调用的函数分配了大量的自动变量,或者涉及许多很深的栈帧,那么所需的栈大小又可能要比默认的大。如果线程栈的虚地址空间都用完了,则可以使用 malloc 或 mmap 来为可替代的栈分配空间,并用 pthread_attr_setstack 函数来改变新建线程的栈位置。其中 stackaddr 参数指定的地址可以用作线程栈的内存范围中的最低可寻址地址(但不一定是栈的开始位置,因为如果栈是从高地址向低地址增长的,则 stackaddr 将是栈的结尾位置),该地址与处理器结构相应的边界应对齐(假设 malloc 和 mmap 所用的虚地址范围与线程栈当前使用的虚地址范围不同)。
pthread_attr_getstacksize 和 pthread_attr_setstacksize 函数可以读取和设置线程属性 stacksize。如果希望改变默认的栈大小,但又不想自己处理线程栈的分配问题,这时使用 pthread_attr_setstacksize 函数就很有用。不过设置 stacksize 属性时,选择的 stacksize 不能小于 PTHREAD_STACK_MIN。
线程属性 guardsize 控制着线程栈末尾之后用以避免栈溢出的扩展内存的大小。该属性默认值是由具体实现来定义的,但常用值是系统页大小。可以把 guardsize 属性设置为 0,这样就不会提供警戒缓冲区。如果修改了 stackaddr 属性,系统也会认为我们将自己管理栈,进而使警戒缓冲区机制无效。如果 guardsize 属性被修改了,操作系统可能会把它取为页大小的整数倍。如果线程的栈指针溢出到警戒区域,应用程序就可能通过信号接收到出错信息。
不过有两个线程属性并没有包含在 pthread_attr_t 结构中,它们是可取消状态和可取消类型。它们影响着线程在响应 pthread_cancel 函数调用时所呈现的行为。
可取消状态属性可以是 PTHREAD_CANCEL_ENABLE 或 PTHREAD_CANCEL_DISABLE。线程可以调用 pthread_setcancelstate 来修改它的可取消状态。
#include <pthread.h> int pthread_setcancelstate(int state, int *oldstate); /* 返回值:若成功,返回 0;否则,返回错误编号 */ void pthread_testcancel(void);
pthread_setcancelstate 把当前的可取消状态设置为 state,并把原来的可取消状态存储在 oldstate 指向的内存单元中,这两步是一个原子操作。
因为 pthread_cancel 不会等待线程终止,所以默认情况下,线程在取消请求发出后会继续运行,直到线程到达某个取消点。取消点是线程检查它是否被取消的一个位置,如果取消了,则按照请求行事。POSIX.1 保证取消点在线程调用下图中的任何函数时都会出现。
线程默认是可取消的,当可取消状态设为 PTHREAD_CANCEL_DISABLE 时,调用 pthread_cancel 并不会杀死线程。相反,取消请求对这个线程来说还处于挂起状态。当取消状态再次变为 PTHREAD_CANCEL_ENABLE 时,线程将在下一个取消点上对所有挂起的取消请求进行处理。
除了上图中的函数,POSIX.1 还指定了下图中的函数作为可选的取消点。
如果应用程序在很长的一段时间内都不会调用上面两个图中的函数,也可以调用 pthread_testcancel 函数在程序中添加自己的取消点。调用该函数时,如果有某个取消请求正处于挂起状态,而且取消并没有置为无效,那么线程就会被取消,否则将不会有任何效果。
上面描述的默认的取消类型也称为推迟取消,调用 pthread_cancel 后,在线程到达取消点之前,并不会出现真正的取消。可以通过 pthread_setcanceltype 来修改取消类型。
#include <pthread.h> int pthread_setcanceltype(int type, int *oldtype); /* 返回值:若成功,返回 0;否则,返回错误编号 */
type 参数可以是 PTHREAD_CANCEL_DEFERRED 或 PTHREAD_CANCEL_ASYNCHRONOUS,该函数把取消类型设置为 type,并把原来的取消类型保存到 oldtype 指向的内存单元中。使用异步取消时,线程就可以在任意时间撤销了。
发表评论
-
打开伪终端设备
2018-07-09 20:50 1249在伪终端概述一节中已对 PTY进行了初步的介绍。尽管 ... -
伪终端概述
2018-06-02 11:05 1538伪终端就是指,一个应用程序看上去像一个终端,但事实上它 ... -
终端窗口大小和 termcap
2018-05-29 22:39 792多数 UNIX 系统都提供了一种跟踪当前终端窗口大小的 ... -
终端规范模式和非规范模式
2018-05-29 00:25 944终端规范模式很简单:发一个读请求,当一行已经输入后,终 ... -
终端标识
2018-05-23 11:18 567尽管控制终端的名字在多数 UNIX 系统上都是 /de ... -
波特率和行控制函数
2018-05-22 07:53 936虽然大多数终端设 ... -
终端属性和选项标志
2018-05-20 07:40 707tcgetattr 和 tcsetattr ... -
终端特殊输入字符
2018-05-17 06:33 810终端支持下表所示的特殊输入字符。 为了更改 ... -
终端 I/O 综述
2018-05-10 07:56 434终端设备可认为是由内核中的终端驱动程序控制的。每个终端 ... -
POSIX 信号量
2018-05-09 00:03 576在XSI IPC通信之信 ... -
XSI IPC 通信之共享存储
2018-04-25 07:18 945在XSI IPC通信之消息队列和XSI IPC通信之信 ... -
XSI IPC通信之信号量
2018-04-17 23:38 613在XSI IPC通信之消 ... -
XSI IPC通信之消息队列
2018-04-15 10:54 491消息队列是消息的链接表,存储在内核中,由消息队列标识符 ... -
XSI IPC 相似特征介绍
2018-02-08 23:48 481有 3 种称作 XSI IPC ... -
IPC 通信之 FIFO
2018-02-06 22:55 413FIFO 也被称为命名管道,未命名的管道只能在两个相关 ... -
IPC 通信之管道
2018-01-30 22:22 383管道是 UNIX 系统 IPC 的最古老但也是最常用的 ... -
readv/writev 函数及存储映射 I/O
2018-01-19 00:57 879readv 和 writev 函数可用于在一次函数调用 ... -
POSIX 异步 I/O
2018-01-16 21:33 452POSIX 异步 I/O 接口为对不同类型的文件进行异 ... -
fcntl 记录锁
2018-01-06 23:48 588记录锁的功能是:当有进程正在读或修改文件的某个部分时, ... -
守护进程惯例
2018-01-06 23:52 433UNIX 系统中,守护进程遵循下列通用惯例。 ...
相关推荐
线程属性包括但不限于: 1. **线程优先级**:操作系统根据线程的优先级决定哪个线程优先获得CPU资源。不同的系统有不同的优先级范围,例如在Unix/Linux中,可以使用nice值来设置线程优先级。 2. **线程同步与互斥*...
线程属性是线程管理的关键部分,它们定义了线程的行为特性,如线程的分离状态、调度策略等。本篇文章将深入探讨Posix线程属性的细节。 首先,线程属性由`pthread_attr_t`结构体表示,使用前需要初始化,通常通过`...
本章主要讨论的是如何通过线程属性对象来定制线程的创建和行为,特别是针对Linux环境。 线程属性对象是一个重要的概念,它允许开发者指定不同于默认行为的线程属性。这些属性可以在创建线程时通过`pthread_create...
该程序是我写的博客“一起talk C栗子吧(第一百二十回:C语言实例--线程属性)”的配套程序,共享给大家使用
通过配置线程调度策略与优先级,可使各线程按照设定的顺序执行,从而达到线程间同步的目的,线程属性配置函数包括: pthread_attr_init(&attr[i]);// 初始化线程属性 pthread_attr_setschedpolicy(&attr[i], SCHED...
在创建joinable状态的线程时,可以通过标准的pthread_create()函数来完成,并传入PTHREAD_CREATE_JOINABLE作为线程属性。完成后,如果需要等待该线程结束,必须调用pthread_join()函数。以下是示例代码: ```c++ #...
线程属性标识符:pthread_attr_t 包含在 pthread.h 头文件中。 //线程属性结构如下: typedef struct { int etachstate; //线程的分离状态 int schedpolicy; //线程调度策略 structsched_param ...
2. **设置线程属性:** - `Suspended`属性控制线程是否在创建后立即启动。如果设为True,线程将被暂停,直到调用`Resume`方法。 - `FreeOnTerminate`属性决定线程结束后是否自动释放。如果设为True,线程对象将在...
- 清除不再需要的线程属性对象。 **设置分离状态** - 配置线程是否自动分离。 **获取分离状态** - 查询线程的分离状态。 **设置栈溢出保护区大小** - 设定线程栈溢出时的安全区大小。 **获取栈溢出保护区大小...
这个函数需要四个参数:线程标识符的指针,线程属性(默认为NULL,表示使用默认属性),线程执行的函数指针,以及传递给线程函数的参数。创建成功时,函数返回0。 2. **线程等待** `pthread_join`函数用于等待一个...
2. 线程的创建:pthread_create() 函数用于创建一个新线程,它的参数包括一个指向pthread_t型变量的指针(用来存储新线程的标识符)、指向线程属性对象的指针(通常传递NULL,使用默认属性)、一个返回类型为void*的...
2. 设定线程属性 在VB6的工程属性中,找到“每个对象对应一个线程”选项,并将其勾选。这样,每一个控件或对象都会在自己的线程上运行,实现真正的多线程。 3. 编写线程代码 在ActiveX EXE工程中编写线程要执行的...
LINUX 线程函数大全是一个详细的线程函数手册,涵盖了线程创建、线程属性、线程结束、线程等待、线程分离、线程数据等多方面的知识点。本手册将详细讲解每个线程函数的使用方法、参数设置、返回值等信息,从而帮助...
本学习资料详细介绍了Linux环境下的多线程编程,涵盖了线程的创建与退出、线程属性设置、以及两种主要的线程同步机制——互斥锁和信号量。 首先,我们来了解一下线程的创建和退出。在Linux中,创建线程主要通过`...
本文将详细介绍Linux下pthread线程库的基本概念、线程创建、线程结束、线程属性修改等方面的知识点。 线程的优点 多线程程序作为一种多任务、并发的工作方式,有以下的优点: 1. 提高应用程序响应:使用多线程...