在 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 操作
有名信号量实现进程间相互排斥功能:
[cpp] view
plaincopy
- #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); //信号量值为 1
- if(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); //信号量值为 1
- if(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 代码例如以下:
[cpp] view
plaincopy
- #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 代码例如以下:
[cpp] view
plaincopy
- #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;
- }
删除有名信号量演示样例代码例如以下:
[cpp] view
plaincopy
- #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_print1
- sem_del("sem_print2"); //删除信号量文件sem_print2
- return 0;
- }
makefile 代码例如以下:
[plain] view
plaincopy
- all:
- gcc sem_del.c -o sem_del -lpthread
- gcc print1.c -o print1 -lpthread
- gcc print2.c -o print2 -lpthread
- clean:
- rm sem_del print1 print2
执行程序时。先把有名信号量删除(sem_del)。再分别执行 print1 和 print2:
转自:http://blog.csdn.net/tennysonsky/article/details/46500417