操作系统线程属性

线程属性

int pthread_create (pthread_t* restrict thread,
                    const pthread_attr_t* restrict attr,
                    void* (*start_routine) (void*),
                    void* restrict arg);
​
//创建线程函数的第二个参数即为线程属性,传空指针表示使用缺省属性。
typedef struct {
    // 分离状态
    int detachstate;
       // PTHREAD_CREATE_DETACHED - 分离线程。
       // PTHREAD_CREATE_JOINABLE(缺省) - 可汇合线程。
​
    // 竞争范围
    int scope;
       // PTHREAD_SCOPE_SYSTEM - 在系统范围内竞争资源(时间片)。
       // PTHREAD_SCOPE_PROCESS(Linux不支持) - 在进程范围内竞争资源。
    
​
    // 继承特性
    int inheritsched;
       // PTHREAD_INHERIT_SCHED(缺省) - 调度属性自创建者线程继承。
       // PTHREAD_EXPLICIT_SCHED - 调度属性由后面两个成员确定。
    
​
    // 调度策略
    nt schedpolicy;
        // SCHED_FIFO - 先进先出策略。
            // 没有时间片。
            // 一个FIFO线程会持续运行,直到阻塞或有高优先级线程就绪。
            // 当FIFO线程阻塞时,系统将其移出就绪队列,待其恢复时再加到同优先级就绪队列的末尾。
            // 当FIFO线程被高优先级线程抢占时,它在就绪队列中的位置不变。
            // 因此一旦高优先级线程终止或阻塞,被抢占的FIFO线程将会立即继续运行。
        // SCHED_RR - 轮转策略。
            // 给每个RR线程分配一个时间片,一但RR线程的时间片耗尽,系统即将移到就绪队列的末尾。
        // SCHED_OTHER(缺省) - 普通策略。
            // 静态优先级为0。任何就绪的FIFO线程或RR线程,都会抢占此类线程。    
​
    // 调度参数
    struct sched_param schedparam;
        // struct sched_param {
        //     int sched_priority; /* 静态优先级 */
        // };
    
​
    // 栈尾警戒区大小(字节)  缺省一页(4096字节)。
    size_t guardsize;
​
    // 栈地址
    void* stackaddr;
​
    // 栈大小(字节)
    size_t stacksize;
} pthread_attr_t;
​
注意:不要手动读写该结构体,而应调用pthread_attr_set/get函数设置/获取具体属性项。
设置线程属性:
初始化线程属性结构体:
pthread_attr_t attr = {}; // 不要使用这种方式
int pthread_attr_init (pthread_attr_t* attr);
设置具体线程属性项:
int pthread_attr_setdetachstate (pthread_attr_t* attr,int detachstate);
int pthread_attr_setscope (pthread_attr_t* attr,int scope);
int pthread_attr_setinheritsched (pthread_attr_t* attr,int inheritsched);
int pthread_attr_setschedpolicy (pthread_attr_t* attr,int policy);
int pthread_attr_setschedparam (pthread_attr_t* attr,const struct sched_param* param);
int pthread_attr_setguardsize (pthread_attr_t* attr,size_t guardsize);
int pthread_attr_setstackaddr (pthread_attr_t* attr,void* stackaddr);
int pthread_attr_setstacksize (pthread_attr_t* attr,size_t stacksize);
int pthread_attr_setstack (pthread_attr_t* attr,void* stackaddr, size_t stacksize);
以设置好的线程属性结构体为参数创建线程:
int pthread_create (pthread_t* restrict thread,
                    const pthread_attr_t* testrict attr,
                    void* (*start_routine) (void*),
                    void* restrict arg);
销毁线程属性结构体:
int pthread_attr_destroy (pthread_attr_t* attr);
获取线程属性:
获取线程属性结构体:
int pthread_getattr_np (pthread_t thread,pthread_attr_t* attr);
获取具体线程属性项:
int pthread_attr_getdetachstate (pthread_attr_t* attr,int* detachstate);
int pthread_attr_getscope (pthread_attr_t* attr,int* scope);
int pthread_attr_getinheritsched (pthread_attr_t* attr,int* inheritsched);
int pthread_attr_getschedpolicy (pthread_attr_t* attr,int* policy);
int pthread_attr_getschedparam (pthread_attr_t* attr,struct sched_param* param);
int pthread_attr_getguardsize (pthread_attr_t* attr,size_t* guardsize);
int pthread_attr_getstackaddr (pthread_attr_t* attr,void** stackaddr);
int pthread_attr_getstacksize (pthread_attr_t* attr,size_t* stacksize);
int pthread_attr_getstack (pthread_attr_t* attr,void** stackaddr, size_t* stacksize);
以上所有函数成功返回0,失败返回错误码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
​
int printattrs (pthread_attr_t* attr) 
{
    printf("------- 线程属性 -------\n");
​
    int detachstate;
    int error = pthread_attr_getdetachstate (attr, &detachstate);
    if (error) 
    {
        fprintf (stderr, "pthread_attr_getdetachstate: %s\n",strerror (error));
        return -1;
    }
    printf("分离状态:  %s\n",
        (detachstate == PTHREAD_CREATE_DETACHED) ? "分离线程" :
        (detachstate == PTHREAD_CREATE_JOINABLE) ? "可汇合线程" :
        "未知");
​
    int scope;
    if ((error = pthread_attr_getscope (attr, &scope)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getscope: %s\n",
            strerror (error));
        return -1;
    }
    printf ("竞争范围:  %s\n",
        (scope == PTHREAD_SCOPE_SYSTEM)  ? "系统级竞争" :
        (scope == PTHREAD_SCOPE_PROCESS) ? "进程级竞争" : "未知");
​
    int inheritsched;
    if ((error = pthread_attr_getinheritsched (attr,
        &inheritsched)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getinheritsched: %s\n",
            strerror (error));
        return -1;
    }
    printf ("继承特性:  %s\n",
        (inheritsched == PTHREAD_INHERIT_SCHED)  ? "继承调用属性" :
        (inheritsched == PTHREAD_EXPLICIT_SCHED) ? "显式调用属性" :
        "未知");
​
    int schedpolicy;
    if ((error = pthread_attr_getschedpolicy(attr,&schedpolicy)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getschedpolicy: %s\n",strerror (error));
        return -1;
    }
    printf ("调度策略:  %s\n",
        (schedpolicy == SCHED_OTHER) ? "普通" :
        (schedpolicy == SCHED_FIFO)  ? "先进先出" :
        (schedpolicy == SCHED_RR)    ? "轮转" : "未知");
​
    struct sched_param schedparam;
    if ((error = pthread_attr_getschedparam (attr, &schedparam)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getschedparam: %s\n",strerror (error));
        return -1;
    }
    printf ("调度优先级:%d\n", schedparam.sched_priority);
​
    size_t guardsize;
    if ((error = pthread_attr_getguardsize(attr, &guardsize)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getguardsize: %s\n",strerror (error));
        return -1;
    }
    printf ("栈尾警戒区:%u字节\n", guardsize);
    /*
    void* stackaddr;
    if ((error = pthread_attr_getstackaddr (attr, &stackaddr)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getstackaddr: %s\n",strerror (error));
        return -1;
    }
    printf ("栈地址:    %p\n", stackaddr);
​
    size_t stacksize;
    if ((error = pthread_attr_getstacksize (attr, &stacksize)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getstacksize: %s\n",strerror (error));
        return -1;
    }
    printf ("栈大小:    %u字节\n", stacksize);
    */
    void* stackaddr;
    size_t stacksize;
    if ((error = pthread_attr_getstack (attr, &stackaddr,&stacksize)) != 0) 
    {
        fprintf (stderr, "pthread_attr_getstack: %s\n",strerror (error));
        return -1;
    }
    printf ("栈地址:    %p\n", stackaddr);
    printf ("栈大小:    %u字节\n", stacksize);
​
    printf("------------------------\n");
​
    return 0;
}
​
void* thread_proc (void* arg) 
{
    pthread_attr_t attr;
    int error = pthread_getattr_np (pthread_self (), &attr);
    if (error) 
    {
        fprintf (stderr, "pthread_getattr_np: %s\n", strerror (error));
        exit (EXIT_FAILURE);
    }
​
    if (printattrs (&attr) < 0)
        exit (EXIT_FAILURE);
​
    exit (EXIT_SUCCESS);
​
    return NULL;
}
​
int main (int argc, char* argv[]) 
{
    int error;
    pthread_attr_t attr, *pattr = NULL;
​
    if (argc > 1) 
    {
        if (strcmp (argv[1], "-s")) 
        {
            fprintf (stderr, "用法:%s [-s]\n", argv[0]);
            return -1;
        }
​
        if ((error = pthread_attr_init (&attr)) != 0) 
        {
            fprintf (stderr, "pthread_attr_init: %s\n",strerror (error));
            return -1;
        }
​
        if ((error = pthread_attr_setdetachstate (&attr,PTHREAD_CREATE_DETACHED)) != 0) 
        {
            fprintf (stderr, "pthread_attr_setdetachstate: %s\n",strerror (error));
            return -1;
        }
​
        if ((error = pthread_attr_setinheritsched (&attr,PTHREAD_EXPLICIT_SCHED)) != 0) 
        {
            fprintf (stderr, "pthread_attr_setinheritsched: %s\n",strerror (error));
            return -1;
        }
​
        if ((error = pthread_attr_setstacksize (&attr, 4096*10)) != 0) 
        {
            fprintf (stderr, "pthread_attr_setstack: %s\n",strerror (error));
            return -1;
        }
​
        pattr = &attr;
    }
​
    pthread_t tid;
    if ((error = pthread_create (&tid, pattr, thread_proc,NULL)) != 0) 
    {
        fprintf (stderr, "pthread_create: %s\n", strerror (error));
        return -1;
    }
​
    if (pattr)
    {
        if ((error = pthread_attr_destroy (pattr)) != 0) 
        {
            fprintf (stderr, "pthread_attr_destroy: %s\n",strerror (error));
            return -1;
        }
    }
​
    pause ();
    return 0;
}

注意:如果man手册查不到线程的相关函数,安装完整版gnu手册:sudo apt-get install glibc-doc。

练习:实现大文件的多线程cp拷贝,对比系统cp命令,哪个速度更快,为什么?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
​
typedef struct Task
{
    char* src;
    char* dest;
    size_t start;
    size_t end;
}Task;
​
void* run(void* arg)
{
    Task* task = arg;
​
    // 打开源文件和目标文件
    FILE* src_fp = fopen(task->src,"r");
    FILE* dest_fp = fopen(task->dest,"a");
    if(NULL == src_fp || NULL == dest_fp)
    {
        perror("fopen");
        return NULL;
    }
​
    // 调整文件的位置指针
    fseek(src_fp,task->start,SEEK_SET);
    fseek(dest_fp,task->start,SEEK_SET);
​
    // 创建缓冲区
    char buf[1024];
    size_t buf_size = sizeof(buf);
​
    for(int i=task->start; i<task->end; i+=buf_size)
    {
        int ret = fread(buf,1,buf_size,src_fp);
        if(0 >= ret)
            break;
        fwrite(buf,1,ret,dest_fp);
    }
​
    fclose(src_fp);
    fclose(dest_fp);
    free(task);
}
​
int main(int argc,const char* argv[])
{
    if(3 != argc)
    {
        puts("Use:./cp <src> <dest>");
        return 0;
    }
​
    // 获取到文件的大小
    struct stat buf;
    if(stat(argv[1],&buf))
    {
        perror("stat");
        return -1;
    }
​
    // 创建出目标文件
    if(NULL == fopen(argv[2],"w"))
    {
        perror("fopen");
        return -2;
    }
​
    // 计算需要的线程数量,以100M为单位
    size_t pthread_cnt = buf.st_size/(1024*1024*100)+1;
​
    // 分配任务
    pthread_t tid;
    for(int i=0; i<pthread_cnt; i++)
    {
        Task* task = malloc(sizeof(Task));
        task->src = (char*)argv[1];
        task->dest = (char*)argv[2];
        task->start = i*1024*1024*100;
        task->end = (i+1)*1024*1024*100;
​
        // 创建子线程并分配任务
        pthread_create(&tid,NULL,run,task);
​
        // 分享子线程
        pthread_detach(tid);
    }
    
    // 结束主线程
    pthread_exit(NULL);
}

多线程并不能提高运行速度,反而可能会降低,所以多线程不适合解决运算密集性问题,而是适合解决等待、阻塞的问题,如果使用进程去等待,会浪费大量资源,所以使用更轻量的线程去等待,节约资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值