Linux多线程实践(三)线程的基本属性设置API

POSIX 线程库定义了线程属性对象 pthread_attr_t ,它封装了线程的创建者可以访问和修改的线程属性。主要包括如下属性:

1. 作用域(scope)

2. 栈尺寸(stack size)

3. 栈地址(stack address)

4. 优先级(priority)

5. 分离的状态(detached state)

6. 调度策略和参数(scheduling policy and parameters)

线程属性对象可以与一个线程或多个线程相关联。当使用线程属性对象时,它是对线程和线程组行为的配置。使用属性对象的所有线程都将具有由属性对象所定义的所有属 性。虽然它们共享属性对象,但它们维护各自独立的线程 ID 和寄存器。

初始化/销毁线程属性

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);  

线程分离属性

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);  

线程栈大小

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);

一般情况下该值我们设置为0,使用系统默认设置的线程栈大小,否则可能会引起程序的可移植性的问题

线程栈溢出保护区大小

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);  

guardsize意思是如果我们使用线程栈超过了设定大小之后,系统还会使用部分扩展内存来防止栈溢出。而这部分扩展内存大小就是guardsize. 不过如果自己修改了栈分配位置的话,那么这个选项失效,效果相当于将guardsize设置为0.

每个线程都存在自己的堆栈,如果这些堆栈是相连的话,访问超过自己的堆栈的话那么可能会修改到其他线程的堆栈。 如果我们设置了guardsize的话,线程堆栈会多开辟guarszie大小的内存,当访问到这块内存时会触发SIGSEGV信号。

线程竞争范围(进程范围内的竞争 or 系统范围内的竞争)

int pthread_attr_getscope(const pthread_attr_t *attr,int *contentionscope);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);  

线程可以在两种竞争域内竞争资源:

1. 进程域(process scope):与同一进程内的其他线程

2. 系统域(system scope):与系统中的所有线程

作用域属性描述特定线程将与哪些线程竞争资源。一个具有系统域的线程将与整个系 统中所有具有系统域的线程按照优先级竞争处理器资源,进行调度。

线程调度策略

int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);  

进程的调度策略和优先级属于主线程,换句话说就是设置进程的调度策略和优先级只 会影响主线程的调度策略和优先级,而不会改变对等线程的调度策略和优先级(注这句话不完全正确)。每个对等线程可以拥有它自己的独立于主线程的调度策略和优先级。

在 Linux 系统中,进程有三种调度策略:SCHED_FIFO(先进先出调度策略)、SCHED_RR(时间片轮转调度算法) 和 SCHED_OTHER(线程一旦开始运行,直到被抢占或者直到线程阻塞或停止为止),线程也不例外,也具有这三种策略。

线程继承的调度策略

int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);  

在 pthread 库中,提供了一个函数,用来设置被创建的线程的调度属性:是从创建者线 程继承调度属性(调度策略和优先级),还是从属性对象设置调度属性。该函数就是:

int pthread_attr_setinheritsched (pthread_attr_t *   attr, int    inherit) 其中,inherit 的值为下列值中的其一:
enum
{
PTHREAD_INHERIT_SCHED, //线程调度属性从创建者线程继承
 PTHREAD_EXPLICIT_SCHED //线程调度属性设置为 attr 设置的属性
};

如果在创建新的线程时,调用该函数将参数设置为 PTHREAD_INHERIT_SCHED 时,那么当修改进程的优先级时,该进程中继承这个优先级并且还没有改变其优先级的所 有线程也将会跟着改变优先级(也就是刚才那句话部分正确的原因)。

线程调度参数(实际上我们一般只关心一个参数:线程的优先级,默认为0)

int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
//sched_param结构体
struct sched_param {
    int sched_priority;     /* Scheduling priority */
};

线程的并发级别

int pthread_setconcurrency(int new_level);
int pthread_getconcurrency(void); 

说明:并发级别仅在N:M线程模型中有效,设置并发级别,给内核一个提示:表示提供给定级别数量的核心线程来映射用户线程是高效的(仅仅是一个提示),默认为0, 内核按照默认的方式进行并发;

我们来写一个例子来运用:

/** 查看线程默认属性 **/
void printThreadAttr()
{
    pthread_attr_t attr;
    pthread_attr_init(&attr);  

    int detachstate;
    pthread_attr_getdetachstate(&attr, &detachstate);
    cout << "detach-state: "
         << (detachstate == PTHREAD_CREATE_JOINABLE ?
             "PTHREAD_CREATE_JOINABLE" : "PTHREAD_CREATE_DETACHED")
         << endl;  

    size_t size;
    pthread_attr_getstacksize(&attr, &size);
    cout << "stack-size: " << size << endl;  

    pthread_attr_getguardsize(&attr, &size);
    cout << "guard-size: " << size << endl;  

    int scope;
    pthread_attr_getscope(&attr, &scope);
    cout << "scope: "
         << (scope == PTHREAD_SCOPE_SYSTEM ?
             "PTHREAD_SCOPE_SYSTEM" : "PTHREAD_SCOPE_PROCESS")
         << endl;  

    int policy;
    pthread_attr_getschedpolicy(&attr, &policy);
    cout << "policy: ";
    switch (policy)
    {
    case SCHED_FIFO:
        cout << "SCHED_FIFO";
        break;
    case SCHED_RR:
        cout << "SCHED_RR";
        break;
    case SCHED_OTHER:
        cout << "SCHED_OTHER";
        break;
    default:
        break;
    }
    cout << endl;  

    int inheritsched;
    pthread_attr_getinheritsched(&attr, &inheritsched);
    cout << "inheritsched: "
         << (inheritsched == PTHREAD_INHERIT_SCHED ?
             "PTHREAD_INHERIT_SCHED" : "PTHREAD_INHERIT_SCHED")
         << endl;  

    struct sched_param param;
    pthread_attr_getschedparam(&attr, ¶m);
    cout << "scheduling priority: " << param.sched_priority << endl;
    cout << "concurrency: " << pthread_getconcurrency() << endl;
    pthread_attr_destroy(&attr);
}  

说明:

绑定属性:

Linux中采用“一对一”的线程机制,也就是一个用户线程对应一个内核线程。绑定属性就是指一个用户线程固定地分配给一个内核线程,因为CPU时间片的调度是面向内核线程(也就是轻量级进程)的,因此具有绑定属性的线程可以保证在需要的时候总有一个内核线程与之对应。而与之对应的非绑定属性就是指用户线程和内核线程的关系不是始终固定的,而是由系统来控制分配的。

分离属性:

分离属性是用来决定一个线程以什么样的方式来终止自己。在非分离情况下,当一个线程结束时,它所占用的系统资源并没有被释放,也就是没有真正的终止。只有当pthread_join()函数返回时,创建的线程才能释放自己占用的系统资源。而在分离属性情况下,一个线程结束时立即释放它所占有的系统资源。这里要注意的一点是,如果设置一个线程的分离属性,而这个线程运行又非常快,那么它很可能在pthread_create()函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用。

时间: 2024-10-12 14:52:12

Linux多线程实践(三)线程的基本属性设置API的相关文章

Linux多线程实践(1) --线程理论

线程概念 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 一切进程至少有一个执行线程; 进程  VS. 线程  1.进程是资源分配(进程需要参与资源的竞争)的基本单位,而线程是处理器调度(程序执行)的最小单位; 2.线程共享进程数据,但也拥有自己的一部分(非常少O(∩_∩)O~)数据,如线程ID.程序计数器.一组寄存器.堆栈.errno(错误代码).信号状态.优先级等; 3.一个进程内部的线程可以共享资源,如代码段.数

Linux多线程实践(2) --线程基本API

POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以"pthread_"开头,要使用这些函数库,要通过引入头文<pthread.h>,而且链接这些线程函数库时要使用编译器命令的"-lpthread"选项[Ubuntu系列系统需要添加的是"-pthread"选项而不是"-lpthread",如Ubuntu 14.04版本,深度Ubuntu等] 1.pthread_create int pt

Linux多线程实践(4) --线程特定数据

线程特定数据 int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *pointer); void * pthread_getspecific(pthread_key_t key); pthread_onc

Linux多线程实践(3) --线程属性

初始化/销毁线程属性 int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr); 线程分离属性 int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); int pthread_attr_setdetachstate(pthread_attr_t *attr, int de

Linux课题实践三——字符集总结与分析

Linux课题实践三——字符集总结与分析 20135318  刘浩晨 字符是各种文字和符号的总称,包括各国家文字.标点符号.图形符号.数字等.字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集.GB2312字符集.BIG5字符集. GB18030字符集.Unicode字符集等. 1.总结ISO.UCS/UTF.GB系列字符集的由来.异同 (1).ISO/IEC ISO/IEC 646:是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定

Linux多线程程序设计------创建线程

1.创建线程 #include<pthread.h> int pthread_create(pthread_t* tidp,const pthread_attr_t *attr,void*(*start_rtn)(void),void*arg) tidp:线程id attr:线程属性(通常为空) start_rtn:线程要执行的函数 arg:start_rtn的参数 Linux多线程程序设计------创建线程,布布扣,bubuko.com

Linux多线程实践(一)线程基本概念和理论

线程概念 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 对于每个进程至少有一个执行线程; 进程  VS. 线程  1.进程是资源分配(进程需要参与资源的竞争)的基本单位,而线程是处理器调度(程序执行)的最小单位; 2.线程共享进程数据,但也拥有自己的一部分数据,如 线程ID.一组寄存器.堆栈.errno(错误代码).信号状态.优先级等; 3.一个进程内部的线程可以共享资源,如代码段.数据段.打开文件和信号等(如下图所

Linux多线程实践(9) --简单线程池的设计与实现

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务(不止一个不同的任务)就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同

Linux多线程实践(四 )线程的特定数据

在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据, 然而在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问.POSIX线程库通过维护一定的数据结构来解决这个问题,这个些数据称为(Thread-specific-data或 TSD). 相关函数如下: int pthread_key_create(pthread_key_t *key, void (*destr