【Linux】线程属性

在使用pthread_create函数创建线程时,我们可以在函数参数列表看到pthread_attr_t *attr这一参数,该参数用于设置线程的属性,一般情况下可使用NULL设置线程属性为默认属性。

线程属性标识符pthread_attr_t包含在pthread.h头文件中

线程属性结构如下:

typedef struct
{ 
   int                   detachstate;   //线程的分离状态
   int                   schedpolicy;   //线程调度策略
   structsched_param     schedparam;    //线程的调度参数
   int                   inheritsched;  //线程的继承性
   int                   scope;         //线程的作用域
   size_t                guardsize;     //线程栈末尾的警戒缓冲区大小
   int                   stackaddr_set; //线程的栈设置
   void*                 stackaddr;     //线程栈的位置
   size_t                stacksize;     //线程栈的大小
}pthread_attr_t;

线程属性主要包含:作用域(scope)、栈的大小(stacksize)、栈地址(stackaddr)、优先级(priority)、分离状态(detachstate)、调度策略和参数(scheduling policy and parameters)。

线程默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样的优先级。

一、线程的作用域(scope)

线程的作用域分为进程域和系统域

  • 进程域:该线程将与同一进程内的其他线程竞争
  • 系统域:该线程将与系统中所有的线程按照优先级竞争处理资源
  • Solaris系统,实际上,从 Solaris 9 发行版开始,系统就不再区分这两个范围

二、线程的绑定状态(binding state)

  1. 非绑定状态
    默认状况下,由系统来控制启动多少轻进程、哪些轻进程来控制哪些线程
  2. 绑定状态
    即某个线程固定的"绑"在一个轻进程之上。由于CPU时间片的调度是面向轻进程的,被绑定的线程则具有较高的响应速度,且绑定的线程可以保证在需要的时候总有一个轻进程可用。

轻进程(LWP:Light Weight Process):内核支持的用户线程,一个进程可有一个或多个轻量级进程,每个轻进程有一个单独的内核线程来支持

三、线程的分离状态(detached state)

  1. 线程的默认属性是非分离状态(joinable),线程退出不会释放资源,原则上需使用使用pthread_join()函数等待线程退出并释放资源,否则会造成系统泄露,pthread_join()函数还会获取线程为何退出的信息。
  2. 具有分离属性(detach)的线程没有其他线程的等待,线出后会自动释放资源,可使用pthread_datach( )函数对线程进行分离,此函数可在不关心线程退出原因,释放线程占用资源时使用。
  3. 注意:如果一个运行很快的线程被设置为分离属性,它很可能在pthread_create函数返回之前就终止了,它终止后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。

四、线程的优先级(priority)

  1. 新线程的优先级为默认为0。
  2. 新线程不继承主线程调度优先级(PTHREAD_EXPLICIT_SCHED)
  3. 仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。

五、线程的栈地址(stack address)

  1. POSIX.1定义了两个常量_POSIX_THREAD_ATTR_STACKADDR 和_POSIX_THREAD_ATTR_STACKSIZE检测系统是否支持栈属性。
  2. 也可以给sysconf函数传递_SC_THREAD_ATTR_STACKADDR或 _SC_THREAD_ATTR_STACKSIZE来进行检测。
  3. 当进程栈地址空间不够用时,指定新建线程使用由malloc分配的空间作为自己的栈空间。通过pthread_attr_setstackaddr和pthread_attr_getstackaddr两个函数分别设置和获取线程的栈地址。传给pthread_attr_setstackaddr函数的地址是缓冲区的低地址(不一定是栈的开始地址,栈可能从高地址往低地址增长)。

六、线程的栈大小(stack size)

  1. 当系统中有很多线程时,可能需要减小每个线程栈的默认大小,防止进程的地址空间不够用
  2. 当线程调用的函数会分配很大的局部变量或者函数调用层次很深时,可能需要增大线程栈的默认大小。
  3. 函数pthread_attr_getstacksize和 pthread_attr_setstacksize提供设置。

七、线程的栈保护区大小(stack guard size)

  1. 在线程栈顶留出一段空间,防止栈溢出。
  2. 当栈指针进入这段保护区时,系统会发出错误,通常是发送信号给线程。
  3. 该属性默认值是PAGESIZE大小,该属性被设置时,系统会自动将该属性大小补齐为页大小的整数倍。
  4. 当改变栈地址属性时,栈保护区大小通常清零。

八、线程的调度策略(schedpolicy)

POSIX标准指定了三种调度策略:先入先出策略 (SCHED_FIFO)、循环策略 (SCHED_RR) 和自定义策略 (SCHED_OTHER)。SCHED_FIFO 是基于队列的调度程序,对于每个优先级都会使用不同的队列。SCHED_RR 与 FIFO 相似,不同的是前者的每个线程都有一个执行时间配额。SCHED_FIFO 和 SCHED_RR 是对 POSIX Realtime 的扩展。SCHED_OTHER 是缺省的调度策略。

  1. 新线程默认使用 SCHED_OTHER 调度策略。线程一旦开始运行,直到被抢占或者直到线程阻塞或停止为止。
  2. SCHED_FIFO
    如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM) 的先入先出线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,则会继续处理该线程,直到该线程放弃或阻塞为止。对于具有进程争用范围 (PTHREAD_SCOPE_PROCESS)) 的线程或其调用进程没有有效用户 ID 0 的线程,请使用 SCHED_FIFO,SCHED_FIFO 基于 TS 调度类。
  3. SCHED_RR
    如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM)) 的循环线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,并且这些线程没有放弃或阻塞,则在系统确定的时间段内将一直执行这些线程。对于具有进程争用范围 (PTHREAD_SCOPE_PROCESS) 的线程,请使用 SCHED_RR(基于 TS 调度类)。此外,这些线程的调用进程没有有效的用户 ID 0。

九、线程并行级别(concurrency)

应用程序使用 pthread_setconcurrency() 通知系统其所需的并发级别。

猜你喜欢

转载自blog.csdn.net/lxf_style/article/details/81140888