linux Posix 信号量 二
一、Posix信号量
1.Posix信号量分为两种:
1. 有名信号量:使用Posix IPC名字标识(有名信号量总是既可用于线程间的同步,又可以用于进程间的同步)
2. 内存信号量:存放在共享内存区中(基于内存的信号量则必须在创建时指定成是否在进程间共享,且在所有进程的共享内存区,具有随进程的持续性)
Posix信号量不必在内核中维护(System V信号量由内核维护),由可能为路径名的名字来标识。
(Posix信号量更常用于进程间同步,互斥锁常用于线程间同步)
2.基本操作:
1. 创建(create):指定初始值。
2. 等待(wait):如果值小于等于0则阻塞,否则将其减一,又称P操作。
3. 挂出(post):将信号量的值加1,加后如果值大于0,则唤醒一个阻塞在等待上的线程,又称V操作。
二值信号量可用于互斥,就像互斥锁一样。但互斥锁必须由锁住它的线程解锁,信号量的挂出却不必由执行过等待的同一线程执行。
信号量的wait和post与条件变量的wait和signal类似,区别是:因为永久的改变了信号量的值,信号量的操作总被记住(会影响到后续的操作);条件变量的signal如果没有线程在等待,该信号将丢失(对后续操作没有影响)。
互斥锁是为上锁而优化的,条件变量是为等待优化的,信号量既可以上锁也可以等待,因此开销更大。
3.Posix信号量操作
有名信号量: |
内存信号量: |
sem_open |
sem_init:需要指定是否共享 |
sem_wait:原子的“测试并减1”操作 |
|
sem_trywait |
|
sem_post:同步技巧中唯一能在信号处理函数内安全调用的操作 |
|
sem_getvalue |
|
sem_close |
sem_destroy |
sem_unlink |
|
即使当前没有进程打开信号量,它的值仍然保持,因此Posix有名信号量至少是随内核持续的。
在父进程中打开的任何信号量,fork后在子进程中仍打开。
关于posix有名信号量使用的几点注意:
1、有名信号量使用sem_unlink从系统中删除。每个信号量有一个引用计数器记录当前的打开次数,sem_unlink必须等待这个数为0时才能把name所指的信号量从文件系统中删除。也就是要等待最后一个sem_close发生。
2、彼此无亲缘关系的进程间需使用信号量时,一般用有名信号量。如果不需要使用关联名字时,可改用内存信号量。
内存信号量需要放在共享内存区中,并由sem_init函数初始化为shared状态才能被不同进程使用,这种情况下它的持续性与共享内存区相同。sem_init总是初始化信号量的值,因此,对于一个给定的信号量,必须小心保证只调用sem_init一次。
3、我们可以用sem_wait来申请共享资源,sem_wait函数可以测试所指定信号量的值,如果该值大于0,那就将它减1并立即返回。我们就可以使用申请来的共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将它减1,函数随后返回。sem_wait操作必须是原子的。sem_wait和sem_trywait的差别是:当所指定信号量的值已经是0时,后者并不将调用线程投入睡眠。相反,它返回一个EAGAIN错误。
当一个线程使用完某个信号量时,它应该调用sem_post来告诉系统申请的资源已经用完。本函数和sem_wait函数的功能正好相反,它把所指定的信号量的值加1,然后唤醒正在等待该信号量值变为正数的任意线程。
4、.Posix有名信号量的值是随内核持续的。也就是说,一个进程创建了一个信号量,这个进程结束后,这个信号量还存在,并且信号量的值也不会改变。
5、当持有某个信号量锁的进程没有释放它就终止时,内核并不给该信号量解锁。
posix有名信号量应用于多线程
#include <semaphore.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <thread.h>
void *thread_function(void *arg); /*线程入口函数*/ void print(pid_t); /*共享资源函数*/ sem_t *sem; /*定义Posix有名信号量*/ int val; /*定义信号量当前值*/
int main(int argc,char *argv[]) { int n=0;
if(argc!=2) { printf(“please input a file name!\n”); exit(1); } sem=sem_open(argv[1],O_CREAT,0644,3); /*打开一个信号量*/
while(n++<5) /*循环创建5个子线程,使它们同步运行*/ { if((pthread_create(&a_thread,NULL,thread_function,NULL))!=0) { perror(“Thread creation failed”); exit(1); } } pthread_join(a_thread,NULL); sem_close(bin_sem); sem_unlink(argv[1]); }
void *thread_function(void *arg) { sem_wait(sem); /*申请信号量*/ print(); /*调用共享代码段*/ sleep(1); sem_post(sem); /*释放信号量*/ printf(“I’m finished,my tid is %d\n”,pthread_self()); }
void print() { printf(“I get it,my tid is %d\n”,pthread_self()); sem_getvalue(sem,&val); printf(“Now the value have %d\n”,val); }
|
程序用循环的方法建立5个线程,然后让它们调用同一个线程处理函数thread_function,在函数里我们利用信号量来限制访问共享资源的线程数。共享资源我们用print函数来代表,在真正编程中它有可以是一个终端设备(如打印机)或是一段有实际意义的代码。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。