Posix线程中的线程属性pthread_attr_t主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。在pthread_create中,把第二个参数设置为NULL的话,将采用默认的属性配置。
pthread_attr_t的主要属性的意义如下:
__detachstate
,表示新线程是否与进程中其他线程脱离同步,
如果设置为
PTHREAD_CREATE_DETACHED
则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。缺省为
PTHREAD_CREATE_JOINABLE
状态。这个属性也可以在线程创建并运行以后用
pthread_detach()
来设置,而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE状态。
__schedpolicy
,表示新线程的调度策略,主要包括
SCHED_OTHER
(正常、非实时)、
SCHED_RR
(实时、轮转法)和
SCHED_FIFO
(实时、先入先出)三种,缺省为
SCHED_OTHER
,后两种调度策略仅对超级用户有效。运行时可以用过pthread_setschedparam()来改变。
__schedparam
,一个
struct sched_param
结构,目前仅有一个
sched_priority
整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为
0
。
__inheritsched
,有两种值可供选择:
PTHREAD_EXPLICIT_SCHED
和
PTHREAD_INHERIT_SCHED
,前者表示新线程使用显式指定调度策略和调度参数(即attr中的值),而后者表示继承调用者线程的值。缺省为
PTHREAD_EXPLICIT_SCHED
。
__scope
,表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。POSIX的标准中定义了两个值:
PTHREAD_SCOPE_SYSTEM
和
PTHREAD_SCOPE_PROCESS
,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅与同进程中的线程竞争CPU。目前LinuxThreads仅实现了
PTHREAD_SCOPE_SYSTEM
一值。
为了设置这些属性,POSIX定义了一系列属性设置函数,包括
pthread_attr_init()、
pthread_attr_destroy()和与各个属性相关的
pthread_attr_get
XXX/
pthread_attr_set
XXX函数。
在设置线程属性
pthread_attr_t 之前,通常先调用pthread_attr_init来初始化,之后来调用相应的属性设置函数。
主要的函数如下:
1、pthread_attr_init
功能: 对线程属性变量的初始化。
头文件: <pthread.h>
函数原型: int pthread_attr_init (pthread_attr_t* attr);
函数传入值:attr:线程属性。
函数返回值:成功: 0
失败: -1
2、pthread_attr_setscope
功能:
设置线程
__scope
属性。scope属性表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。POSIX的标准中定义了两个值:
PTHREAD_SCOPE_SYSTEM
和
PTHREAD_SCOPE_PROCESS
,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅与同进程中的线程竞争CPU。默认为PTHREAD_SCOPE_PROCESS。
目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。
头文件: <pthread.h>
函数原型:
int
pthread_attr_setscope
(pthread_attr_t* attr, int scope);
函数传入值:attr: 线程属性。
scope:
PTHREAD_SCOPE_SYSTEM,
表示与系统中所有线程一起竞争CPU时间,
PTHREAD_SCOPE_PROCESS,表
示仅与同进程中的线程竞争CPU
函数返回值得:同1。
3、pthread_attr_setdetachstate
功能:
设置线程
detachstate
属性。该表示新线程是否与进程中其他线程脱离同步,如果设置为
PTHREAD_CREATE_DETACHED
则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。缺省为
PTHREAD_CREATE_JOINABLE
状态。这个属性也可以在线程创建并运行以后用pthread_detach()来设置,而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE状态。
头文件: <phread.h>
函数原型:
int
pthread_attr_setdetachstate
(pthread_attr_t* attr, int detachstate);
函数传入值:attr:线程属性。
detachstate:
PTHREAD_CREATE_DETACHED,
不能用pthread_join()来同步,且在退出时自行释放所占用的资源
PTHREAD_CREATE_JOINABLE,
能用pthread_join()来同步
函数返回值得:同1。
4、pthread_attr_setschedparam
功能: 设置线程
schedparam
属性,即调用的优先级。
头文件: <pthread.h>
函数原型: i
nt
pthread_attr_setschedparam
(pthread_attr_t* attr, struct sched_param* param);
函数传入值:attr:线程属性。
param:线程优先级。
一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0
函数返回值:同1。
5、pthread_attr_getschedparam
功能: 得到线程优先级。
头文件: <pthread.h>
函数原型:
int
pthread_attr_getschedparam
(pthread_attr_t* attr, struct sched_param* param);
函数传入值:attr:线程属性;
param:线程优先级;
函数返回值:同1。
示例1:
#include
<stdlib.h>
#include
<stdio.h>
#include
<errno.h>
#include
<pthread.h>
static
void
pthread_func_1
(
void
);
static
void
pthread_func_2
(
void
);
int
main
(
int
argc
,
char
**
argv
)
{
pthread_t
pt_1
=
0
;
pthread_t
pt_2
=
0
;
pthread_attr_t
atrr
=
{
0
};
int
ret
=
0
;
/*初始化属性线程属性*/
pthread_attr_init
(&
attr
);
pthread_attr_setscope
(&
attr
,
PTHREAD_SCOPE_SYSTEM
);
pthread_attr_setdetachstate
(&
attr
,
PTHREAD_CREATE_DETACHED
);
ret
=
pthread_create
(&
pt_1
,
&
attr
,
pthread_func_1
,
NULL
);
if
(
ret
!=
0
)
{
perror
(
"pthread_1_create"
);
}
ret
=
pthread_create
(&
pt_2
,
NULL
,
pthread_func_2
,
NULL
);
if
(
ret
!=
0
)
{
perror
(
"pthread_2_create"
);
}
pthread_join
(
pt_2
,
NULL
);
return
0
;
}
static
void
pthread_func_1
(
void
)
{
int
i
=
0
;
for
(;
i
<
6
;
i
++)
{
printf
(
"This is pthread_1.\n"
);
if
(
i
==
2
)
{
pthread_exit
(
0
);
}
}
return
;
}
static
void
pthread_func_2
(
void
)
{
int
i
=
0
;
for
(;
i
<
3
;
i
++)
{
printf
(
"This is pthread_2.\n"
);
}
return
;
}
从上面事例中,可以得到这么一个结果,就是线程一的线程函数一结束就自动释放资源,线程二就得等到pthread_join来释放系统资源。
结束!
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
sem_init函数是Posix信号量操作中的函数。sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程之间共享。如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在这个进程的所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量)。
如果 pshared 是非零值,那么信号量将在进程之间共享,并且应该定位共享内存区域(见 shm_open(3)、mmap(2) 和 shmget(2))。因为通过 fork(2) 创建的孩子继承其父亲的内存映射,因此它也可以见到这个信号量。所有可以访问共享内存区域的进程都可以用 sem_post(3)、sem_wait(3) 等等操作信号量。初始化一个已经初始的信号量其结果未定义。
返回值
sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。
用下面一组函数(系统调用)来实现。
int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem);
具体要Include什么头文件,在你的系统上man sem_init吧。
这组函数是POSIX标准的无名信号量函数,另外还有具名信号亮,这个嘛,等下回再说。
第一个参数:信号量名
看一个例子,比如有两个线程都要往打印机上打东西,但是同一时刻只能打一个。
那么首先用sem_init初始化一个信号量,注意pshared表示允许几个进程共享该信号量,一般设0用于进程内的多线程共享,要看是否支持进程共享,请查看下你的系统的man手册。
第三个参数value表示可用的资源的数目,即信号灯的数目,咱们这儿只有1个打印机所以设成1。
然后线程调用sem_wait取获取这个信号灯,第一个线程一看,有1个,他就拿到了,然后可以继续后继操作,此时信号灯自动减1,变成0个。那么第二个线程调用sem_wait时就会阻塞在这儿了。
第一个线程完成打印后,调用sem_post释放信号灯,信号灯数目变成1,将会唤醒等待的第二个线程,然后第二个线程接着打印。
最后当所有任务完成后,主线程调用sem_destroy释放这个信号量。