线程属性的相关设置详解 - 详解
- pthread_attr_t 结构体
线程属性结构如下:
                typedef struct
                {
 int                            detachstate;     //线程的分离状态
                       int                            schedpolicy;     //线程调度策略
                       struct sched_param    schedparam;    //线程的调度参数
                       int                            inheritsched;    //线程的继承性
                       int                            scope;             //线程的作用域
                       size_t                        guardsize;        //线程栈尾警戒缓冲区大小
                       int                             stackaddr_set;
                       void *                       stackaddr;       // 线程栈的位置
size_t                        stacksize;       // 线程栈的大小
                }pthread_attr_t;
       detachstate,线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join() 函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
       通俗的说也就是:我们知道一般我们要等待(pthread_join)一个线程的结束,主要是想知道它的结束状态,否则等待一般是没有什么意义的!但是如果对一些线程的终止态我们压根就不想知道,那么就可以使用“分离”属性,那么我 们就无须等待管理,只要线程自己结束了,自己释放资源就可以。
detachstate有两种取值:
  PTHREAD_CREATE_DETACHED:     分离状态启动
  PTHREAD_CREATE_JOINABLE:      聚合状态启动线程
schedpolicy,表示新线程的调度策略,主要包括:
SCHED_OTHER(正常、非实时)
SCHED_RR(实时、轮转法)
SCHED_FIFO(实时、先入先出)
缺省为SCHED_OTHER,
schedparam,一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,
/usr/include /bits/sched.h
     struct sched_param
     {
            int sched_priority;    //!> 参数的本质就是优先级
     };注意:大的权值对应高的优先级!
                    系统支持的最大和最小的优先级值可以用函数:
                    sched_get_priority_max和sched_get_priority_min得到!
inheritsched,继承性决定调度的参数是从创建的进程中继承还是使用在 
            schedpolicy和schedparam属性中显式设置的调度信息,
可设置参数:
            PTHREAD_INHERIT_SCHED: 新的线程继承创建线程的策略和参数!
            PTHREAD_EXPLICIT_SCHED:新的线程继承策略和参数来自于
 schedpolicy和schedparam属性中显式
设置的调度信息!
scope,表示线程间竞争资源的范围
POSIX的标准中定义了两个值:PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,
目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。
scope有两种取值:
PTHREAD_SCOPE_SYSTEM: 与系统中所有线程一起竞争资源 PTHREAD_SCOPE_PROCESS: 仅与同进程中的线程竞争CPU
示例:
 3. 线程属性及属性设置
        3.1 线程属性结构体
                typedef struct
                {
                       int                            detachstate;     //线程的分离状态
                       int                            schedpolicy;     //线程调度策略
                       struct sched_param             schedparam;    //线程的调度参数
                       int                            inheritsched;    //线程的继承性
                       int                            scope;             //线程的作用域
                       size_t                         guardsize;        //线程栈尾警戒缓冲区大小
                       int                            stackaddr_set;
                       void *                         stackaddr;       // 线程栈的位置
                       size_t                         stacksize;       // 线程栈的大小
                }pthread_attr_t;
    3.2. 线程属性设置流程
          1)  初始化线程属性对象
                 pthread_attr_init
                 头文件:      #include <pthread.h>  
             函数原型:    int pthread_attr_init(pthread_attr_t *attr);
             函数功能:    初始化线程属性对象
             函数参数:    attr:待初始化的线程属性对象
             函数返回值:  成功返回0
                      失败返回错误码                
          2)  设置指定的属性
                  int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
                      int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
          3)  利用属性创建线程
          4)  回收线程属性对象
                 pthread_attr_destroy
                 头文件:      #include <pthread.h>  
             函数原型:    int pthread_attr_destroy(pthread_attr_t *attr);
             函数功能:    回收线程属性对象
             函数参数:    attr:待回收的线程属性对象
             函数返回值:  成功返回0
                      失败返回错误码
#include       // 提供Unix系统调用
#include      // 多线程编程
#include        // 标准输入输出
#include       // 字符串处理
#include       // 标准库函数
int thread_num = 0;      // 全局变量,用于线程计数
// 线程执行函数
void* routine(void* argp)
{
    thread_num--;        // 线程结束时减少计数
    return NULL;         // 线程正常退出
}
int main(int argc, char** argv)
{
     // 声明线程属性变量
     pthread_attr_t attr;
     // 初始化线程属性变量
     pthread_attr_init(&attr);
     // 获取和设置线程栈大小
     size_t stacksize = 0;
     // 设置线程栈大小为4MB
     pthread_attr_setstacksize(&attr, 4 * 1024 * 1024);
     // 获取实际设置的栈大小
     pthread_attr_getstacksize(&attr, &stacksize);
     printf("缺省线程栈空间大小:%lu MB\n", stacksize / 1024 / 1024);
     // 设置线程为分离状态(detached)
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
     // 创建线程,使用自定义属性
     pthread_t id;
     pthread_create(&id, &attr, routine, NULL);
     thread_num++;       // 增加线程计数
     // 销毁线程属性变量(释放资源)
     pthread_attr_destroy(&attr);
     /*
     // 被注释的代码:尝试等待分离线程(会失败)
     int error = 0;
     if(error = pthread_join(id, NULL))
     {
        printf("join:%s\n", strerror(error));
     }
     */
     // 忙等待,直到线程计数为0
     while(thread_num)   ;
     return 0;
}     关键机制详解
1. 线程属性设置
pthread_attr_t attr;
pthread_attr_init(&attr);  // 初始化属性对象2. 栈大小设置
pthread_attr_setstacksize(&attr, 4 * 1024 * 1024);  // 设置为4MB
pthread_attr_getstacksize(&attr, &stacksize);       // 验证设置栈大小说明:
- 默认栈大小通常为2-10MB,取决于系统和编译器 
- 设置更大的栈用于需要大量局部变量的线程 
- 设置更小的栈用于创建大量线程的场景 
3. 线程分离状态
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);分离状态 vs 可连接状态:
| 状态 | 特点 | 是否需要pthread_join | 资源回收 | 
|---|---|---|---|
| PTHREAD_CREATE_JOINABLE(默认) | 可等待线程结束 | 需要 | 手动调用pthread_join回收 | 
| PTHREAD_CREATE_DETACHED | 分离状态 | 不能等待 | 自动回收资源 | 
4. 被注释的pthread_join代码
/*
if(error = pthread_join(id, NULL))
{
   printf("join:%s\n", strerror(error));
}
*/这里被注释是有原因的:
- 线程被设置为分离状态后,不能再调用 - pthread_join()
- 如果取消注释,会返回 - EINVAL错误
5. 线程同步机制
while(thread_num) ;  // 忙等待,直到thread_num为0工作原理:
- 主线程创建子线程时: - thread_num++(变为1)
- 子线程结束时: - thread_num--(变为0)
- 主线程在忙等待循环中检测到这个变化后退出 
程序执行流程
- 主线程初始化属性,设置栈大小和分离状态 
- 主线程创建分离线程,增加线程计数 
- 主线程进入忙等待循环 
- 子线程执行,减少线程计数 
- 子线程退出,系统自动回收资源(因为是分离线程) 
- 主线程检测到thread_num为0,退出循环 
- 程序结束 
潜在问题和改进
1. 忙等待(Busy Waiting)问题
while(thread_num) ;  // CPU占用率高改进方案:使用条件变量
#include 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* routine(void* argp) {
    pthread_mutex_lock(&mutex);
    thread_num--;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
    return NULL;
}
// 主线程中:
pthread_mutex_lock(&mutex);
while(thread_num) {
    pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex); 2. 内存排序问题
thread_num--;  // 可能存在可见性问题改进方案:使用原子操作或互斥锁
#include 
atomic_int thread_num = 0;
// 或者使用互斥锁保护 3. 完整的改进版本
#include 
#include 
#include 
#include 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int thread_num = 0;
void* routine(void* argp) {
    pthread_mutex_lock(&mutex);
    thread_num--;
    printf("子线程结束,剩余线程数: %d\n", thread_num);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
    return NULL;
}
int main() {
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    // 设置线程属性
    pthread_attr_setstacksize(&attr, 4 * 1024 * 1024);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    // 创建线程
    pthread_t id;
    pthread_mutex_lock(&mutex);
    pthread_create(&id, &attr, routine, NULL);
    thread_num++;
    printf("创建线程,当前线程数: %d\n", thread_num);
    pthread_mutex_unlock(&mutex);
    // 等待线程结束
    pthread_mutex_lock(&mutex);
    while(thread_num > 0) {
        pthread_cond_wait(&cond, &mutex);
    }
    pthread_mutex_unlock(&mutex);
    pthread_attr_destroy(&attr);
    printf("所有线程结束,程序退出\n");
    return 0;
}    这个程序很好地演示了线程属性的使用,特别是栈大小设置和分离状态的配置。
 
                    
                
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号