Linux的POSIX线程属性
创建POSIX线程的函数为
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
第1个参数为线程句柄(类似于文件描述符),第3个参数为线程启动函数(输入void*、返回void*,因为指向任何结构体/基本数据类型的指针都可以被看作void*,而void*一般都可以显式强制转换成指向对应类型的指针甚至整型,这是不支持纯C编程的常见技巧),第4个参数为传递给线程启动函数的参数。
而第2个参数一般都设置为NULL,此时采用默认的线程属性()。但是有需求的时候还是得去设置,即使是TLPI上也没有深入线程属性而只是在29.8线程属性一节给出了个例子。于是我通过结合手册以及查看pthread.h来深入了解其用法。
首先贴出TLPI上线程属性的设置示例(的完整版),该线程使用了分离(detach)属性,即线程创建后自动分离,而无需调用pthread_detach函数
// thread_attrib.c: 线程属性使用示例
// 编译方式: gcc thread_attrib.c -pthread
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h> // 检查错误码errnum, 若不为0则输出msg以及错误码相关信息
static inline void checkErrnum(int errnum, const char* msg)
{
if (errnum != 0) {
fprintf(stderr, "%s error: %s\n", msg, strerror(errnum));
exit(1);
}
} // 线程启动函数, 将输入看作字符串类型
static inline void* threadFunc(void* arg)
{
printf("%s\n", (char*) arg);
return NULL;
} int main()
{
int s; // 错误码 // 初始化线程属性
pthread_attr_t attr;
s = pthread_attr_init(&attr);
checkErrnum(s, "pthread_attr_init"); // 设置线程分离状态, 此属性保证线程
s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
checkErrnum(s, "pthread_attr_setdetachstate"); // 使用attr属性创建线程
pthread_t tid;
s = pthread_create(&tid, &attr, threadFunc, (void*) "Hello world!");
checkErrnum(s, "pthread_create"); // 销毁线程属性
s = pthread_attr_destroy(&attr);
checkErrnum(s, "pthread_attr_destroy"); sleep(1); // main线程休眠, 保证创建线程的threadFunc函数能够执行完毕
return 0;
}
需要注意的一点是:使用pthread_attr_init初始化线程属性,使用完(即传入pthread_create)后需要使用pthread_attr_destory销毁,从而释放相关资源。
同时也可以发现,线程属性的设置方式并不像那样简单,一般纯C中设置属性往往是通过亦或运算来设置不同类型。
比如系统调用open的第3个参数可以用S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH这样4个定义为整型的宏进行亦或运算来表示rw-r--r--的读/写/执行权限。
而线程属性的设置,对每个属性都有单独的函数,而每个函数都有各自的选项,比如这里的pthread_attr_setdetachstate,关键词是detachstate(分离状态)。第2个参数这里选择了PTHREAD_CREATE_DETACHED,代表线程创建后立刻分离
于是查看线程属性类型的定义
union pthread_attr_t
{
char __size[__SIZEOF_PTHREAD_ATTR_T];
long int __align;
};
#ifndef __have_pthread_attr_t
typedef union pthread_attr_t pthread_attr_t;
# define __have_pthread_attr_t
#endif
之前open的第3个参数相当于是0b0001、0b0010、0b0100这种类型的值求亦或,可以看做是位(bit)数组,数组的每一位只能是0或1,而每一个线程属性都可以有多个值,于是pthread_attr_t则是一个char数组,char的取值有256个,也就是说,每一个线程属性理论上可以支持最多256个可选值。数组大小_SIZEOF_PTHREA_ATTR_T则是由系统类型以及WORDSIZE来决定。
这里通过查看glib库的头文件pthread.h来一探究竟,看看线程属性有哪些。线程属性的设置函数的前缀都是pthread_attr_set,所以查找以此为前缀的函数即可。我将找到的函数列表整理如下
1、线程分离状态(Detach state),默认是JOINABLE,即其他线程可以通过pthread_join函数来取得该线程的返回结果(“连接”);DETACHED则是线程创建时即分离,无法被其他线程连接。
/* Detach state. */
enum
{
PTHREAD_CREATE_JOINABLE,
#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE
PTHREAD_CREATE_DETACHED
#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED
};
/* Get detach state attribute. */
extern int pthread_attr_getdetachstate (const pthread_attr_t *__attr,
int *__detachstate)
__THROW __nonnull ((, )); /* Set detach state attribute. */
extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,
int __detachstate)
__THROW __nonnull (());
2、线程栈末尾之后用以避免栈溢出的扩展内存的大小,若设置为0,则代表这种机制无效
/* Get the size of the guard area created for stack overflow protection. */
extern int pthread_attr_getguardsize (const pthread_attr_t *__attr,
size_t *__guardsize)
__THROW __nonnull ((, )); /* Set the size of the guard area created for stack overflow protection. */
extern int pthread_attr_setguardsize (pthread_attr_t *__attr,
size_t __guardsize)
__THROW __nonnull (());
3、调度参数,类型为结构体struct sched_param,第1个参数为优先级,其他的参数未知。可移植的做法就是设置线程优先级。
/* The official definition. */
struct sched_param {
int __sched_priority;
};
/* Return in *PARAM the scheduling parameters of *ATTR. */
extern int pthread_attr_getschedparam (const pthread_attr_t *__restrict __attr,
struct sched_param *__restrict __param)
__THROW __nonnull ((, )); /* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */
extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr,
const struct sched_param *__restrict
__param) __THROW __nonnull ((, ));
4、调度策略,SCHED_OTHER为默认值(分时调度策略),SCHED_FIFO和SCHED_RR均为实时调度策略,前者是先到先服务,后者是时间片轮转。
具体细节可以参考文章
线程调度策略SCHED_RR(轮转法)和SCHED_FIFO(先进先出)之对比
/* Return in *POLICY the scheduling policy of *ATTR. */
extern int pthread_attr_getschedpolicy (const pthread_attr_t *__restrict
__attr, int *__restrict __policy)
__THROW __nonnull ((, )); /* Set scheduling policy in *ATTR according to POLICY. */
extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy)
__THROW __nonnull (());
// bits/sched.h
/* Scheduling algorithms. */
#define SCHED_OTHER 0
#define SCHED_FIFO 1
#define SCHED_RR 2
5、调度器的继承模式,默认是INHERIT,继承自父线程的调度优先级,只有设置为EXPLICIT,自己“显式”设置的调度策略、优先级才会起作用。
/* Scheduler inheritance. */
enum
{
PTHREAD_INHERIT_SCHED,
#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED
PTHREAD_EXPLICIT_SCHED
#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED
};
/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */
extern int pthread_attr_getinheritsched (const pthread_attr_t *__restrict
__attr, int *__restrict __inherit)
__THROW __nonnull ((, )); /* Set scheduling inheritance mode in *ATTR according to INHERIT. */
extern int pthread_attr_setinheritsched (pthread_attr_t *__attr,
int __inherit)
__THROW __nonnull (());
6、调度内容的作用域,SYSTEM代表该线程与系统的所有线程竞争资源,PROCESS代表该线程与进程中的其他线程竞争资源。
/* Scope handling. */
enum
{
PTHREAD_SCOPE_SYSTEM,
#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM
PTHREAD_SCOPE_PROCESS
#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS
};
/* Return in *SCOPE the scheduling contention scope of *ATTR. */
extern int pthread_attr_getscope (const pthread_attr_t *__restrict __attr,
int *__restrict __scope)
__THROW __nonnull ((, )); /* Set scheduling contention scope in *ATTR according to SCOPE. */
extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope)
__THROW __nonnull (());
7、线程的栈地址
/* Return the previously set address for the stack. */
extern int pthread_attr_getstackaddr (const pthread_attr_t *__restrict
__attr, void **__restrict __stackaddr)
__THROW __nonnull ((, )) __attribute_deprecated__; /* Set the starting address of the stack of the thread to be created.
Depending on whether the stack grows up or down the value must either
be higher or lower than all the address in the memory block. The
minimal size of the block must be PTHREAD_STACK_MIN. */
extern int pthread_attr_setstackaddr (pthread_attr_t *__attr,
void *__stackaddr)
__THROW __nonnull (()) __attribute_deprecated__;
8、当前使用的最小栈地址的大小,当设置这个值时,栈的大小不能小于PTHREAD_STACK_MIN,不能大于系统的限制(用命令ulimit -s查看)
/* Return the currently used minimal stack size. */
extern int pthread_attr_getstacksize (const pthread_attr_t *__restrict
__attr, size_t *__restrict __stacksize)
__THROW __nonnull ((, )); /* Add information about the minimum stack size needed for the thread
to be started. This size must never be less than PTHREAD_STACK_MIN
and must also not exceed the system limits. */
extern int pthread_attr_setstacksize (pthread_attr_t *__attr,
size_t __stacksize)
__THROW __nonnull (());
9、线程栈的地址和大小(需要定义宏__USE_XOPEN2K)
#ifdef __USE_XOPEN2K
/* Return the previously set address for the stack. */
extern int pthread_attr_getstack (const pthread_attr_t *__restrict __attr,
void **__restrict __stackaddr,
size_t *__restrict __stacksize)
__THROW __nonnull ((, , )); /* The following two interfaces are intended to replace the last two. They
require setting the address as well as the size since only setting the
address will make the implementation on some architectures impossible. */
extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
size_t __stacksize) __THROW __nonnull (());
#endif
10、线程的亲和性,(需要定义宏__USE_GNU)
#ifdef __USE_GNU
/* Thread created with attribute ATTR will be limited to run only on
the processors represented in CPUSET. */
extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr,
size_t __cpusetsize,
const cpu_set_t *__cpuset)
__THROW __nonnull ((, )); /* Get bit set in CPUSET representing the processors threads created with
ATTR can run on. */
extern int pthread_attr_getaffinity_np (const pthread_attr_t *__attr,
size_t __cpusetsize,
cpu_set_t *__cpuset)
__THROW __nonnull ((, ));#endif
Linux的POSIX线程属性的更多相关文章
- Linux中-POSIX 线程详解
一种支持内存共享的简捷工具 摘自https://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/ 线程是有趣的 了解如何正确运用线 ...
- Linux系统编程 —线程属性
在之前的章节中,我们在调用pthread_create函数创建线程时,第二个参数(即线程属性)都是设为NULL,即使用默认属性.一般情况下,使用默认属性已经可以解决我们开发过程中的大多数问题. 但是, ...
- LInux多线程编程----线程属性pthread_attr_t
1.每个POSIX线程有一个相连的属性对象来表示属性.线程属性对象的类型是pthread_attr_t,pthread_attr_t 在文件/usr/include/bits/pthreadtypes ...
- POSIX 线程取消点的 Linux 实现
http://blog.csdn.net/stevenliyong/article/details/4364039 原文链接:http://blog.solrex.cn/articles/linux- ...
- Linux多线程实践(3) --线程属性
初始化/销毁线程属性 int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *att ...
- Linux posix线程库总结
由于历史原因,2.5.x以前的linux对pthreads没有提供内核级的支持,所以在linux上的pthreads实现只能采用n:1的方式,也称为库实现. 线程的实现,经历了如下发展阶段: Linu ...
- Linux 线程属性函数总结
1.初始化一个线程对象的属性 int pthread_attr_init(pthread_attr_t *attr); 返回值:若是成功返回0,否则返回错误的编号 形 参: attr 指向一个线程属性 ...
- Linux线程属性总结
线程属性标识符:pthread_attr_t 包含在 pthread.h 头文件中. //线程属性结构如下: typedef struct { int etachs ...
- Linux互斥和同步应用程序(一):posix线程和线程之间的相互排斥
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流.请勿用于商业用途] 有了进程的概念,为何还要使用线程呢? 首先,回 ...
随机推荐
- [转载]Java操作Excel文件的两种方案
微软在桌面系统上的成功,令我们不得不大量使用它的办公产品,如:Word,Excel.时至今日,它的源代码仍然不公开已封锁了我们的进一步应用和开发.在我们实际开发企业办公系统的过程中,常常有客户这样子要 ...
- C# 设计模式巩固 - 工厂方法模式
前言 实在编不出来了~ 介绍 - 工厂方法模式 官方定义:(下面摘自百度百科)工厂方法模式(FACTORY METHOD)是一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中 ...
- Matching (2)
HALCON 10.0 II-B 3.1 Gray-Value-Based Matching 基于灰度的匹配是一个非常经典的方法,它仅适用于对象的不模糊,不缺失,灰度值不变化.适用于对象旋转转.注意 ...
- CentOS7 修改默认时区为 北京时间
首先同步时间 yum install -y ntpdate ntpdate -u cn.pool.ntp.org 然后设置中国时区(北京时间) timedatectl set-timezone Asi ...
- 文件目录tree显示,python
#/usr/bin/python import os def travelTree(currentPath, count=0): if not os.path.exists(currentPath): ...
- windows下的一些命令
dir 相当于linux下的ls clear 清屏 netstat 活动连接 | 管道命令 findstr 查询类似linux的grep tasklist 查看进程列表 taskkill 杀死进程 d ...
- c# Request.Files["xx"]取不到值解决办法
- SQL SERVER - set statistics time on的理解
一.set statistics time on的作用 显示分析.编译和执行各语句所需的毫秒数. 二.语法 SET STATISTICS TIME { ON | OFF } 注释 1.当 SET ST ...
- MATROSKA 文件格式
MATROSKA 文件格式 1.EBML (Extensible Binary Meta Language): EBML语言使用不定长整数,这种方式相对于固定长度的32位/64位字长的整数值更节约空间 ...
- js函数的伪重载
这也是今天写东西是遇到的一个问题,导致我联想起了函数重载的问题. 在javascript中是没有函数重载机制的,对于用惯了java开发的同学可能就表示吃惊了,我屮艸芔茻,函数 没有重载?那怎么搞?!! ...