进程同步与互斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥。它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。前面我们学习了无名信号量的使用(详情请看《无名信号量》),这里我们学习有名信号量的使用。

1)创建一个有名信号量

所需头文件:

#include <fcntl.h>

#include <sys/stat.h>

#include <semaphore.h>

当有名信号量存在时使用:sem_t *sem_open(const char *name, int oflag);当有名信号量不存在时使用:sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);

功能:

创建一个有名信号量。

参数:

name:信号量文件名。注意,不能指定路径名。因为有名信号量,默认放在/dev/shm 里,,如下图:

flags:sem_open() 函数的行为标志。

mode:文件权限(可读、可写、可执行)的设置。

value:信号量初始值。

返回值:

成功:信号量的地址

失败:SEM_FAILED

2)关闭有名信号量

所需头文件:

#include <semaphore.h>

int sem_close(sem_t *sem);功能:

关闭有名信号量。

参数:

sem:指向信号量的指针。

返回值:

成功:0

失败:-1

3)删除有名信号量文件

所需头文件:

#include <semaphore.h>

int sem_unlink(const char *name);功能:

删除有名信号量的文件。

参数:

name:有名信号量文件名。

返回值:

成功:0

失败:-1

4)信号量 PV 操作

用法和《POSIX 无名信号量》一样,详情请点此链接。

有名信号量实现进程间互斥功能:

#include<stdio.h>#include<semaphore.h>#include<fcntl.h>#include<unistd.h>#include<sys/stat.h>#include<sys/types.h>void printer(sem_t *sem, char *str){sem_wait(sem);//信号量减一while(*str!='\0'){putchar(*str);fflush(stdout);str++;sleep(1);}printf("\n");sem_post(sem);//信号量加一}int main(int argc, char *argv[]){pid_t pid;sem_t *sem = NULL;pid = fork(); //创建进程if(pid<0){ //出错perror("fork error");}else if(pid == 0){ //子进程//跟open()打开方式很相似,不同进程只要名字一样,那么打开的就是同一个有名信号量sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1if(sem == SEM_FAILED){ //有名信号量创建失败perror("sem_open");return -1;}char *str1 = "hello";printer(sem, str1); //打印sem_close(sem); //关闭有名信号量_exit(1);}else if(pid > 0){ //父进程//跟open()打开方式很相似,不同进程只要名字一样,那么打开的就是同一个有名信号量sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1if(sem == SEM_FAILED){//有名信号量创建失败perror("sem_open");return -1;}char *str2 = "world";printer(sem, str2); //打印sem_close(sem); //关闭有名信号量wait(pid, NULL); //等待子进程结束}sem_unlink("name_sem");//删除有名信号量return 0;}

运行结果如下:

有名信号量实现进程间同步功能(print2 先打印,再到 print1 打印):

print1.c 代码如下:

#include <fcntl.h>/* For O_* constants */#include <sys/stat.h>/* For mode constants */#include <semaphore.h>#include <stdio.h>void print(sem_t *print1, sem_t *print2){int i = 0;while(1){sem_wait(print1);i++;printf("int print1 i = %d\n", i);sem_post(print2);}}int main(int argc, char **argv){sem_t *print1, *print2;print1 = sem_open("sem_print1", O_CREAT, 0777, 0); if(SEM_FAILED == print1){perror("sem_open");}print2 = sem_open("sem_print2", O_CREAT, 0777, 1);if(SEM_FAILED == print2){perror("sem_open");}print(print1, print2);return 0;}print2.c 代码如下:#include <fcntl.h>/* For O_* constants */#include <sys/stat.h>/* For mode constants */#include <semaphore.h>#include <stdio.h>void print(sem_t *print1, sem_t *print2){int i = 0;while(1){sem_wait(print2);i++;printf("in print2 i = %d\n", i);sleep(1);sem_post(print1);}}int main(int argc, char **argv){sem_t *print1, *print2;print1 = sem_open("sem_print1", O_CREAT, 0777, 0); if(SEM_FAILED == print1){perror("sem_open");}print2 = sem_open("sem_print2", O_CREAT, 0777, 1); if(SEM_FAILED == print2){perror("sem_open");}print(print1, print2);return 0;}删除有名信号量示例代码如下:#include <semaphore.h>#include <stdio.h>void sem_del(char *name){int ret;ret = sem_unlink(name);if(ret < 0){perror("sem_unlink");}}int main(int argc, char **argv){sem_del("sem_print1"); //删除信号量文件sem_print1sem_del("sem_print2"); //删除信号量文件sem_print2return 0;}makefile 代码如下:all:gcc sem_del.c -o sem_del -lpthreadgcc print1.c -o print1 -lpthreadgcc print2.c -o print2 -lpthreadclean:rm sem_del print1 print2运行程序时,先把有名信号量删除(sem_del),再分别运行 print1 和 print2:

本教程示例代码下载请点此处。

获致幸福的不二法门是珍视你所拥有的、遗忘你所没有的

进程同步与互斥:POSIX有名信号量

相关文章:

你感兴趣的文章:

标签云: