- POSIX信号量
- 1. 基本概念
- 2. POSIX匿名信号量
- 2. 定义
- 2.2 初始化
- 2.3 P/V *** 作
- 3. POSIX具名信号量
- 3.1 创建和打开
- 3.2 P/V *** 作
- 3.3 关闭、删除和其他注意事项
POSIX信号量与IPC信号量组中的信号量元素的逻辑完全一样,但POSIX信号量 *** 作更加简便,接口更加易用。在多进程多线程中运用广泛。
POSIX信号量分成两种:
POSIX匿名信号量
通常用在线程间
只存在于内存,在文件系统中不可见
POSIX具名信号量
通常用在进程间
存在于文件系统/dev/shm中,可被不同进程 *** 作
#include2.2 初始化sem_t s;
#includeint sem_init(sem_t *sem, int pshared, unsigned int value);
接口说明:
sem:待初始化信号量指针
pshared:指定信号量的作用范围
0:作用于进程内的线程间
非0:作用于进程间
value:信号量的初始值
示例
sem_t s; int main() { // 初始化POSIX匿名信号量: // 将其设定为在本进程内的个线程间使用 // 并将其初始值设定为1 sem_init(&s, 0, 1); }2.3 P/V *** 作
POSIX信号量(不管是匿名的还是具名的)的 P/V *** 作相对于systemV的信号量组而言,接口非常简单:
#include
int sem_wait(sem_t *sem); // P *** 作
int sem_post(sem_t *sem); // V *** 作
接口说明:
P *** 作即申请资源,因此 sem_wait()在资源不足时会阻塞,V *** 作是释放资源,且V *** 作永远不会阻塞
示例
#include3. POSIX具名信号量sem_t s; char buf[100]; void *routine(void *arg) { while(1) { // 申请信号量-1,输出字符串的长度 p *** 作 sem_wait(&s); printf("%dn", strlen(buf)); } } int main() { // 初始化,信号量初始值为0 sem_init(&s, 0, 0); pthread_t t; pthread_create(&t, NULL, routine, NULL); while(1) { fgets(buf, 100, stdin); // 输入字符串后,释放信号量+1 v *** 作 sem_post(&s); } }
POSIX 具名信号量主要用在多进程间同步互斥,其 P/V *** 作与匿名版本无异,其最大的特点是存在于文件系统 /dev/shm 中,可以被系统中任意有权限的进程打开。
3.1 创建和打开POSIX 具名信号量使用如下接口创建:
#include#include #include sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
说明
与文件IO函数 open() 类似,sem_open() 也提供了两个版本,初建时需要指定文件权限 mode 和初始值 value,后续再打开使用时则无需指定。
示例
// 在进程 a.c 中创建具名信号量
int main() { // 创建有名信号量,参数1代表初始值为1 sem_t *s = sem_open("mysem", O_CREAT, 0666, 1); }
// 在进程 b.c 中打开具名信号量
int main() { // 打开具名信号量 sem_t *s = sem_open("mysem", O_RDWR); }
编译程序 a.c(注意要加线程库 -lpthread)并运行该程序,便会在系统 /dev/shm/ 产生对应的文件:
gec@ubuntu:~$ gcc a.c -o a -lpthread
gec@ubuntu:~$ ./a
gec@ubuntu:~$ ls -l /dev/shm/
总用量 4
-rw-rw-r-- 1 gec gec 32 Nov 26 18:27 sem.mysem
gec@ubuntu:~$
与匿名信号量完全一致:
#includeint sem_wait(sem_t *sem); // P *** 作 int sem_post(sem_t *sem); // V *** 作
示例
// a.c
int main() { sem_t *s = sem_open("mysem", O_CREAT, 0666, 0); printf("An"); sem_post(s); // V *** 作 } // b.c int main() { sem_t *s = sem_open("mysem", O_RDWR); // 等待A执行完毕,才执行B sem_wait(s); // P *** 作 printf("Bn"); }
信号量的V *** 作就像一个远程开关,控制另一个进程的进度:在进程A尚未执行 sem_post(s) 之前,进程B会一直在 sem_wait(s) 静静等待,这就是多进程进度控制。
注意,上述程序 a.c 和程序 b.c 是两个独立的程序,彼此之间没有任何共享的变量和数据,他们通过基于文件系统的具名信号量达成协同。
POSIX 具名信号量跟文件 *** 作非常类似,打开之后会在内核需要对其维护,因此在不再需要的时候应该予以关闭:
sem_close(s);
另外,即使所有进程都关闭了信号量并且退出,具名信号量对应的文件是不会消失的,并且会保留所有 P/V *** 作后的值,如果不再需要这个文件本身,则除了可以直接在文件系统中删除外,也可以使用如下接口删除:
sem_unlink("mysem");
上文提到,具名信号量会将所有的 P/V *** 作后的值,因此向上述程序 a.c 如果连续执行三遍,那么信号量的值将会被 +3 ,因此程序 b.c 可以连续进行三次 P *** 作。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)