小言_互联网的博客

Linux C 系统编程(11)线程管理 线程控制

363人阅读  评论(0)

线程控制:设置线程的属性属于高级操作,该属性会影响到内核的行为,所以一般不会对这些属性进行修改,尤其是线程内核堆栈的大小。


1 创建和销毁属性结构

在使用pthread_create函数创建一个线程的时候,可以通过第2个参数attr设置线程的属性,设置为NULL则使用系统默认属性来创建线程,线程的属性被组织在一个结构体中。结构体如下:


  
  1. //线程属性结构
  2. typedef struct
  3. {
  4. int detachstate; //线程的分离状态
  5. int schedpolicy; //线程调度策略
  6. struct sched_param schedparam; //线程的调度参数
  7. int inheritsched; //线程的继承性
  8. int scope; //线程的作用域
  9. size_t guardsize; //线程栈末尾的警戒缓冲区大小
  10. int stackaddr_set;
  11. void * stackaddr; //线程栈的位置
  12. size_t stacksize; //线程栈的大小
  13. } pthread_attr_t;

使用pthread_attr_init来初始化属性结构,使用pthread_attr_destroy函数来销毁一个不用的属性结构。函数原型如下:


  
  1. //pthread_attr_init 函数为属性结构分配内存空间,通过这个参数返回首地址。
  2. int pthread_attr_init (pthread_attr_t *attr);
  3. //pthread_attr_destroy将前者分配的内存空间释放;
  4. int pthread_attr_destroy (pthread_attr_t *attr);
  5. 参数attr:一个指向线程属性结构的指针。
  6. 函数执行成功返回 0,失败返回错误号。

注意:两者要配套出现,否则会造成内存泄漏(一个是地址分配,一个是地址释放)。


2 线程属性

2.1 线程分离状态

线程的分离状态:决定一个线程以什么样的方式来终止自己。状态有两种:

  1. 非分离状态(默认):此时原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
  2. 分离状态:分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。

使用pthread_attr_getdetachstate来获取线程的分离状态,使用pthread_attr_setdetachstate来设置线程的分离状态。函数原型如下:


  
  1. int pthread_attr_getdetachstate(const pthread_attr_t *attr,int *detachstate);
  2. int pthread_attr_setdetachstate(pthread_attr_t *attr,intdetachstate);
  3. 参数:
  4. Attr 线程属性变量
  5. Detachstate 线程的分离状态属性,有两个值
  6. PTHREAD_CREATE_DETACHED,以分离状态启动线程;
  7. PTHREAD_CREATE_JOINABLE,以非分离状态启动线程;
  8. 返回值:若成功返回 0,若失败返回 -1

使用的说明:如果我们在创建线程时就知道不需要了解线程的终止状态,则可以pthread_attr_t结构中的detachstate线程属性,让线程以分离状态启动。

2.2 栈的设置

pthread_create 创建线程时,若不指定分配堆栈的大小,系统会分配默认值,查看默认值方法如下:

ulimit -s

使用pthread_attr_getstacksize来获取线程的栈大小,使用pthread_attr_setstacksize来设置线程的栈大小。函数原型如下:


  
  1. int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
  2. int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
  3. 参数:
  4. attr            线程属性变量
  5. inheritsched    线程的栈大小,stacksize以字节为单位
  6. 返回值:若成功返回 0,若失败返回

就个人职业范围来讲,这个设置主要在嵌入式环境中。因为在嵌入式中内存不是很大,采用默认值则会导致内存不足,因此需要在创建线程前提前设置这个栈。

2.3 调度策略

线程的调度策略是可以通过API来设置的,使用pthread_attr_getschedpolicy来获取调度策略,使用pthread_attr_setschedpolicy来设置调度策略。函数原型如下:


  
  1. int pthread_attr_getschedpolicy(const pthread_attr_t*attr,int *policy);
  2. int pthread_attr_setschedpolicy(pthread_attr_t *attr,intpolicy);
  3. 参数:
  4. attr 线程属性变量
  5. policy 调度策略
  6. SCHED_FIFO(先进先出),支持优先级 1 -99
  7. SCHED_RR(轮转法),支持优先级 1 -99
  8. SCHED_OTHER(其它),不支持优先级
  9. 返回值:
  10. 若成功返回 0,若失败返回 -1

SCHED_FIFO和SCHED_RR策略的详细说明:

  1. SCHED_FIFO策略:会很快开始执行,除非有更高优先级的线程已经在运行或者阻塞自己。
  2. SCHED_RR(轮循)策略:设置时间片。

注意:

  1. 如果有一个SCHED_RR策略的线程执行了超过一个固定的时期(时间片间隔)没有阻塞,而另外的SCHED_RR或SCHBD_FIPO策略的相同优先级的线程准备好时,运行的线程将被抢占以便准备好的线程可以执行。
  2. 当有SCHED_FIFO或SCHED_RR策赂的线程在一个条件变量上等持或等持加锁同一个互斥量时,它们将以优先级顺序被唤醒。即,如果一个低优先级的SCHED_FIFO线程和一个高优先织的SCHED_FIFO线程都在等待锁相同的互斥且,则当互斥量被解锁时,高优先级线程将总是被首先解除阻塞。

2.4 调度参数

线程的调度参数是可以通过API来设置的,使用pthread_attr_getschedparam来获取调度参数,使用pthread_attr_setschedparam来设置调度参数。函数原型如下:


  
  1. int pthread_attr_getschedparam(const pthread_attr_t*attr,struct sched_param *param);
  2. int pthread_attr_setschedparam(pthread_attr_t *attr,conststruct sched_param *param);
  3. 参数:
  4. attr 线程属性变量
  5. param sched_param结构
  6. 返回值:若成功返回 0,若失败返回 -1

这里涉及一个结构体sched_param,它的实现如下:


  
  1. struct sched_param
  2. {
  3. int sched_priority; // 该参数的本质就是优先级
  4. };

结构sched_param的子成员sched_priority控制一个优先权值(值越大优先权越高)。系统支持的最大和最小优先权值可以用sched_get_priority_max函数和sched_get_priority_min函数分别得到。

特殊说明:如果不是编写实时程序,不建议修改线程的优先级。调度策略如果不正确使用会导致程序错误,导致死锁等各种问题。比如在多线程应用程序中为线程设置不同的优先级别,有可能因为共享资源而导致优先级倒置。

2.5 继承性

继承性决定调度的参数是从创建的进程中继承还是使用在schedpolicy和schedparam属性中显式设置的调度信息。使用pthread_attr_getinheritsched来获取继承性的信息,使用pthread_attr_setinheritsched来设置继承性的信息。对应的函数原型如下:


  
  1. int pthread_attr_getinheritsched(const pthread_attr_t*attr,int *inheritsched);
  2. int pthread_attr_setinheritsched(pthread_attr_t *attr,intinheritsched);
  3. 参数:
  4. attr 线程属性变量
  5. inheritsched 线程的继承性
  6. PTHREAD_INHERIT_SCHED表示新现成将继承创建线程的调度策略和参数
  7. PTHREAD_EXPLICIT_SCHED表示使用在schedpolicy和schedparam属性中显式设置的调度策略和参数
  8. 返回值:若成功返回 0,若失败返回 -1

Pthreads不为inheritsched指定默认值,如果关心线程的调度策略和参数,必须先设置该属性。


3 pthread系列的函数查询方法

关于pthread系列的函数还有很多,如果用到,我们并不能直接使用Linux下的man命令查询,而是安装pthread线程man page手册,安装命令如下:

sudo apt-get install manpages-posix-dev

验证安装:

man -k pthread 

可以列出pthread。查看当前pthread库的版本:

getconf GNU_LIBPTHREAD_VERSION

使用线程库时,gcc编译需要加上 -lpthread(小写L)


转载:https://blog.csdn.net/vviccc/article/details/105166567
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场