Linux中POSIX信号量代码解析(P/V操作)

您所在的位置:网站首页 信号量的pv操作方法是 Linux中POSIX信号量代码解析(P/V操作)

Linux中POSIX信号量代码解析(P/V操作)

2024-07-08 17:38| 来源: 网络整理| 查看: 265

文章目录 POSIX信号量 1. 基本概念2. POSIX匿名信号量2. 定义2.2 初始化2.3 P/V 操作 3. POSIX具名信号量3.1 创建和打开3.2 P/V 操作3.3 关闭、删除和其他注意事项

POSIX信号量 1. 基本概念

POSIX信号量与IPC信号量组中的信号量元素的逻辑完全一样,但POSIX信号量操作更加简便,接口更加易用。在多进程多线程中运用广泛。 POSIX信号量分成两种:

POSIX匿名信号量 通常用在线程间 只存在于内存,在文件系统中不可见 POSIX具名信号量 通常用在进程间 存在于文件系统/dev/shm中,可被不同进程操作

2. POSIX匿名信号量 2. 定义 #include sem_t s; 2.2 初始化 #include int 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操作永远不会阻塞 示例

#include sem_t s; char buf[100]; void *routine(void *arg) { while(1) { // 申请信号量-1,输出字符串的长度 p操作 sem_wait(&s); printf("%d\n", 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); } } 3. POSIX具名信号量

POSIX 具名信号量主要用在多进程间同步互斥,其 P/V 操作与匿名版本无异,其最大的特点是存在于文件系统 /dev/shm 中,可以被系统中任意有权限的进程打开。

3.1 创建和打开

POSIX 具名信号量使用如下接口创建:

#include /* For O_* constants */ #include /* For mode constants */ #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:~$

3.2 P/V 操作

与匿名信号量完全一致:

#include int 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("A\n"); sem_post(s); // V操作 } // b.c int main() { sem_t *s = sem_open("mysem", O_RDWR); // 等待A执行完毕,才执行B sem_wait(s); // P操作 printf("B\n"); }

信号量的V操作就像一个远程开关,控制另一个进程的进度:在进程A尚未执行 sem_post(s) 之前,进程B会一直在 sem_wait(s) 静静等待,这就是多进程进度控制。 注意,上述程序 a.c 和程序 b.c 是两个独立的程序,彼此之间没有任何共享的变量和数据,他们通过基于文件系统的具名信号量达成协同。

3.3 关闭、删除和其他注意事项

POSIX 具名信号量跟文件操作非常类似,打开之后会在内核需要对其维护,因此在不再需要的时候应该予以关闭:

sem_close(s);

另外,即使所有进程都关闭了信号量并且退出,具名信号量对应的文件是不会消失的,并且会保留所有 P/V 操作后的值,如果不再需要这个文件本身,则除了可以直接在文件系统中删除外,也可以使用如下接口删除:

sem_unlink("mysem");

上文提到,具名信号量会将所有的 P/V 操作后的值,因此向上述程序 a.c 如果连续执行三遍,那么信号量的值将会被 +3 ,因此程序 b.c 可以连续进行三次 P 操作。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3