Linux 多线程编程( POSIX )( 三)------->信号灯—转
一.POSIX 有名信号灯
所谓有名就是给一个类似句柄的key。
1. 创建并初始化有名信号灯
函数:sem_open
#include <semaphore.h>
sem_t * sem_open( const char *name, int oflag, mode_t mode, unsigned int val );
参数:
name:信号灯的名称
oflag:选择创建或者打开一个现有的信号灯
mode:权限位(进程中已经讲过,差不多)
val:信号灯的初始值
成功时返回指向信号灯的指针,出错时为SEM_FAILED
oflag可以取值为:0,O_CREAT(创建),O_CREAT | O_EXCL(没有指定就创建)
if oflag 指定了参数有O_CREAT,那么后面的mode和val参数是必须的!!!
注意:val的值大小不能超过SEM_VALUE_MAX < 32767。
一般有两种信号灯: 互斥信号灯(二值),所以val = 1
计数信号灯,一般val > 1
注意参数 O_CREAT与O_CREAT | O_EXCL的区别
>>>>>>>: 前者的意思是: 如果所需信号灯尚未存在,那就创建并初始化它
所以即使是已经存在此信号量,指定此参数也不会报错。
后者则不一样,其实是保证了唯一性,也就是if已经有了,那么就会报错。
2. sem_close:关闭有名信号灯
#include <semaphore.h>
int sem_close( sem_t * sem ); //!> 注意是以key关闭
若成功则返回0,否则返回-1。
>>>>>:
一个进程终止时,内核还对其上仍然打开着的所有有名信号灯自动执行这样的信号灯关闭操作。
但应注意的是关闭一个信号灯并没有将它从系统中删除。
有名信号灯是随内核持续的,即使当前没有进程打开着某个信号灯,它的值仍然保持。
3. sem_unlink:从系统中删除信号灯
#include <semapthore.h>
int sem_unlink( const char * name ); //!> 注意是以name删除的!
若成功则返回0,否则返回-1。 //!> 注意与sem_close的区别
4. sem_getvalue: 测试信号灯
#include <semaphore.h>
int sem_getvalue( sem_t * sem, int * val );
若成功则返回0,否则返回-1。
>>>>>:
sem_getvalue在由val指向的正数中返回所指定信号灯的当前值。如果该信号灯当前已上锁,
那么返回值或为0,或为某个负数,其绝对值就是等待该信号灯解锁的线程数。
5. 等待共享src(互斥使用):sem_wait 和 sem_trywait
#include <semaphore.h>
int sem_wait( sem_t * sem );
int sem_trywait( sem_t * sem );
若成功则返回0,否则返回-1。
具体执行:
我们可以用sem_wait来申请共享资源,sem_wait函数可以测试所指定信号
灯的值,如果该值大于0,那就将它减1并立即返回。我们就可以使用申请来的共享
资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时
再将它减1,函数随后返回。sem_wait操作必须是原子操作。
( 注意与SYSTEM V 中的P, V 操作是一样的... ... )
对于sem_trywait一般的功能与sem_wait差不多,主要差别是:当所指定信号灯的值已
经是0时,后者并不将调用线程投入睡眠。相反,它返回一个EAGAIN错误。
6. 解锁操作( 就是V操作 ),也就是有sem_wait相反的操作!!!
sem_post
#include <semaphore.h>
int sem_post( sem_t * sem );
若成功则返回0,否则返回-1。
注意:信号灯创建OK后,就是已经存在于system中了,即使是不同的程序中使用都是可以的,只要没有被删除而且没有被其他程序占用!!!
二.基于内存的信号灯
由应用程序分配信号灯的内存空间,然后由系统初始化它们的值。
1. 初始化和关闭信号灯:sem_init和sem_destroy
#include <semaphore.h>
int sem_init( sem_t * sem, int shared, unsigned int value );
int sem_destroy( sem_t * sem );
参数:
sem 指向信号灯的指针
shared 作用范围
value 信号灯初始值
若成功则返回0,否则返回-1。
shared参数:如果shared为0,那么待初始化的信号灯是在
同一进程的各个线程共享的,否则该信号灯是在进程间共享的。
当shared为不零时,该信号灯必须存放在即将使用它的所有进程
都能访问的某种类型的共享内存中。
sem_destroy用于关闭信号灯!
注意:除了sem_open和sem_close外,其它的poisx有名信号灯函数
都可以用于基于内存的信号灯。
>>>>>:
注意与“有名信号灯”的主要区别:
1.sem_open不需要类型与shared的参数,有名信号灯总是可以在不同进程间共享的。
2.注意:对于一个给定的信号灯,我们必须小心保证只调用一次sem_init。
( 当然可以使用pthread_once_t来进行初始化 )
3.posix有名信号灯是通过内核持续的,一个进程创建一个信号灯,另外的进程可以
通过该信号灯的外部名(创建信号灯使用的文件名)来访问它。posix基于内存的
信号灯的持续性却是不定的,如果基于内存的信号灯是由单个进程内的各个线程
共享的,那么该信号灯就是随进程持续的,当该进程终止时它也会消失。如果某
个基于内存的信号灯是在不同进程间同步的,该信号灯必须存放在共享内存区中,
这要只要该共享内存区存在,该信号灯就存在。