首页 > 代码库 > 第10章 线程控制(2)_线程属性和线程优先级

第10章 线程控制(2)_线程属性和线程优先级

3. 线程属性

3.1 线程属性结构体

(1)pthread_attr_t结构体

技术分享 

(2)线程属性初始化和销毁

头文件

#include <pthread.h>

函数

int pthread_attr _init(pthread_attr_t* attr); //初始化

int pthread_attr_destroy(pthread_attr_t* attr); //销毁

返回值

成功返回0,否则返回错误编号

3.2 设置和获取分离属性

头文件

#include <pthread.h>

函数

int pthread_attr _getdetachstat (const pthread_attr_t* attr, int* detachstate); //获取分离属性

int pthread_attr_setdetachstat (const pthread_attr_t* attr, int detachstate); //设置分离属性

返回值

成功返回0,否则返回错误编号

参数

detachstate的取值:

①PTHREAD_CREATE_JOINABLE(默认值) //正常启动线程

②PTHREAD_CREATE_DETACHED         //以分离状态启动线程

备注

(1)以默认方式启动的线程,在线程结束后不会自动释放占用的系统资源,要在主控线程中调用pthread_join()后才会释放。

(2)以分离状态启动的线程,在线程结束后会自动释放所占有的系统资源。

(3)分离属性在网络通讯中使用的较多。

【编程实验】线程分离属性

//pthread_detach.c

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

//线程函数
void* th_fn(void* arg)
{
    int i = 0;
    int sum = 0;
    for(i=1; i<=100; i++){
        sum += i;
    }
    return (void*)sum;
}

//输出线程属性
void out_state(pthread_attr_t* attr)
{
    int state = 0;
    //获取分离属性
    if(pthread_attr_getdetachstate(attr, &state)!=0){
        perror("getdetachstate error");
    }else{
        if(state == PTHREAD_CREATE_JOINABLE){
            printf("joinable state\n");//正常状态启动
        }else if(state == PTHREAD_CREATE_DETACHED){
            printf("detached state\n");//分离状态启动
        }else{
            printf("error state\n");
        }
    }
}

int main(void)
{
    int err;
    pthread_t default_th, detach_th;
    //定义线程属性
    pthread_attr_t attr;
    //对线程属性初始化
    pthread_attr_init(&attr);
    //输出分离属性:默认值
    out_state(&attr); 
    
    //方式1:以分离属性的默认值方式启动子线程(正常启动)
    if((err = pthread_create(&default_th, &attr, th_fn, (void*)0)) != 0){
        perror("pthread create error");
    }

    int res = 0;
    if((err = pthread_join(default_th, (void*)&res)) != 0){
        perror("pthread join error");
    }else{
        printf("default return is %d\n", (int)res);
    }
    printf("----------------------------------------\n");

    //方式2:设置线程属性为分离状态启动
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    out_state(&attr);
    //以分离状态启动子线程
    if((err = pthread_create(&detach_th, &attr, th_fn, (void*)0))!=0){
        perror("pthread create error");
    }
    
    //注意:分离状态的子线程,调用pthread_join将失败!
    if((err = pthread_join(detach_th, (void*)&res)) != 0){
        //perror("pthread join error");
        fprintf(stderr, "%s\n", strerror(err));
    }else{
        printf("detach return is %d\n", (int)res);
    }
    

    //销毁线程属性
    pthread_attr_destroy(&attr);

    printf("0x%lx finished\n", pthread_self());
    sleep(1);
   
    return 0;
}
/*输出结果
 joinable state          //正常状态启动 
 default return is 5050
 ----------------------------------------
 detached state          //分离状态启动
 Invalid argument        //调用pthread_join失败!
 0xb77976bf finished
 */

3.3 线程优先级设置

(1)调度策略和获取最高/最低优先级

头文件

#include <pthread.h>

#include <sched.h>

函数

//设置调度策略

int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy);

//获取可设置的最高、最低优先级

int sched_get_priority_max(int policy);

int sched_get_priority_min(int policy);

返回值

成功返回0,否则返回错误编号

参数

policy的取值

①SCHED_OTHER:分时调度策略,不支持优先级使用。(默认调度策略)

②SCHED_FIFO:实时调度策略。一旦占用CPU则一直运行。直到有更高优先级到达或自己放弃

③SCHED_RR:实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。

(2)获取和设置优先级

头文件

#include <pthread.h>

#include <sched.h>

函数

int pthread_attr_setschedparam(pthread_addr_t* attr, const struct sched_param* param); //设置优先级

int  pthread_attr_getschedparam(const pthread_attr_t* attr, struct sched_param* param); //获取优先级

返回值

成功返回0,否则返回错误编号

参数

struct sched_param
{
    int32_t sched_priority; //所要设定的线程优先级(1-99),数值越大,优先级越高。
};

【编程实验】设置线程优先级

//pthread_priority.c

#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>

/*改变线程调度策略和优先级*/

//显示线程的调度策略和优先级
void show_attr(int threadid, int policy, int priority)
{
    printf("thread%d ", threadid);
    switch(policy)
    {
    case SCHED_OTHER:
        printf("policy = SCHED_OTHER");
        break;
    case SCHED_RR:
        printf("policy = SCHED_RR");
        break;
    case SCHED_FIFO:
        printf("policy = SCHED_FIFO");
        break;
    default:
        printf("policy = UNKNOW");
        break;
    }
    printf(" priority = %d\n", priority);
}

void* th_fn(void* arg)
{
    int id = (int)arg;

    int i, j;
    int policy;
    struct sched_param param;
    
    //获取当前线程的线程调度策略和优先级
    pthread_getschedparam(pthread_self(), &policy, &param);
    show_attr(id, policy, param.sched_priority);

    for(i=1; i<10;i++){
        for(j=1;j<100000000;j++);
        printf("%d thread%d\n", i, id);
    }

    printf("thread%d exit\n", id);
    
    return (void*)0;
}

int main(void)
{
    pthread_t t1, t2, t3;
    struct sched_param param;
    pthread_attr_t attr1, attr2, attr3;
    
    pthread_attr_init(&attr1); 
    pthread_attr_init(&attr2);
    pthread_attr_init(&attr3);
    
    //线程1按默认的调度策略和优先级:SCHED_OTHER

    //线程2的调度策略为SCHED_RR,优先级为21
    param.sched_priority = 21;
    pthread_attr_setschedpolicy(&attr2, SCHED_RR);//调度策略
    pthread_attr_setschedparam(&attr2, &param);   //优先级
    pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED); //不继承父线程的调度策略,
                                                                  //而是由用户自己指定调度策略

    //线程3的为SCHED_RR调度,优先级为51
    param.sched_priority = 51; //数值越大,优先级越高!
    pthread_attr_setschedpolicy(&attr3, SCHED_RR);
    pthread_attr_setschedparam(&attr3, &param);
    pthread_attr_setinheritsched(&attr3, PTHREAD_EXPLICIT_SCHED);

    //创建3个子线程
    pthread_create(&t1, &attr1, th_fn, (void*)1);
    pthread_create(&t2, &attr2, th_fn, (void*)2);
    pthread_create(&t3, &attr3, th_fn, (void*)3);
   
   //等待子线程结束
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);

    //销毁线程属性
    pthread_attr_destroy(&attr1);
    pthread_attr_destroy(&attr2);
    pthread_attr_destroy(&attr3);

    return 0;
}
 /* 输出结果
 * thread2 policy = SCHED_RR priority = 11
 * 1 thread2
 * 2 thread2
 * 3 thread2
 * thread1 policy = SCHED_OTHER priority = 0 
 * thread3 policy = SCHED_RR priority = 51  //线程1被线程3抢占
 * 1 thread3
 * 2 thread3
 * 3 thread3
 * 4 thread3
 * 5 thread3
 * 6 thread3
 * 7 thread3
 * 8 thread3
 * 9 thread3
 * thread3 exit
 * 4 thread2
 * 5 thread2
 * 6 thread2
 * 7 thread2
 * 8 thread2
 * 9 thread2
 * thread2 exit
 * 1 thread1
 * 2 thread1
 * 3 thread1
 * 4 thread1
 * 5 thread1
 * 6 thread1
 * 7 thread1
 * 8 thread1
 * 9 thread1
 * thread1 exit
 *从输出结果看,得到如下结论:
 *(1)线程1为普通调度策略(SCHED_OTHER),线程2和线程3为时间片轮转实时调度策略(SCHED_RR)
 *(2)优先级高的线程3并没有最先运行,但获的时间片更多。
 *(3)线程2、3为实时线程,所以最先运行完,线程1为普通线程最后运行结束。
 */

第10章 线程控制(2)_线程属性和线程优先级