linux进程间通信之Posix 信号量用法详解代码举例
Posted wudymand
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux进程间通信之Posix 信号量用法详解代码举例相关的知识,希望对你有一定的参考价值。
Posix信号量不同于System V信号量的信号量集,Posix信号量是单一的信号量,分为有名信号量和无名信号量。
Posix有名信号量是使用Posix IPC名字标示的信号量,可用于进程和线程间的同步;Posix无名信号量是指基于内存的信号量,存放在共享内存区中,用于进程与线程间的同步。
Posix有名信号量可以是内核维护,也可以在文件系统中维护,这取决于信号量对应的路径名是否映射到了真正的磁盘文件上,如果有映射到则在文件系统中维护,否则在内核中维护,Posix有名信号量由函数sem_open(),sem_close(),sem_unlink(),sem_wait(),sem_trywait(),sem_post(),sem_getvalue()来操作使用。
Posix无名信号量根据sem_init()函数调用时的输入参数不同而分为进程间共享和线程间共享,函数原型int sem_init(sem_t *sem,int shared,unsigned int value); 的第二个参数shared若为0,则表示是线程间共享;若shared是1,则表示是进程间共享,同时第一个参数变量sem_t数据类型变量sem必须驻留在所有希望共享它的进程所共享的内存区中。Posix无名信号量由函数sem_init(),sem_destroy(),sem_wait(),sem_trywait(),sem_post(),sem_getvalue()来操作使用。
Posix信号量相关函数的原型及头文件:
#include <semaphore.h>
sem_t *sem_open(const char*name,int oflag,.../*mode_t mode, unsigned int value*/);
功能:创建一个新的有名信号量或打开一个已存在的有名信号量
返回值:若成功返回指向信号量的指针,该指针用作sem_close(),sem_wait(),sem_trywait(),sem_post,sem_getvalue()的参数;若出错返回SEM_FAILED.
参数:name为路径名;oflag可以是0,O_CREAT或O_CREAT|O_EXCL;mode参数可选是指定权限位,在O_CREAT是有效;value参数可选是指定信号量的初始值,不能超过SEM_VALUE_MAX,二值信号量的初始值通常为1,计数信号量初始值通常大于1。
int sem_close(sem_t *sem);
功能:关闭由sem_open()打开的有名信号量。
返回值:若成功返回0,若失败返回-1
int sem_unlink(const char *name);
功能:从系统中真正删除信号量
返回值:若成功返回0,若失败返回-1
int sem_wait(sem_t *sem);
功能:测试指定信号量的值,如果值大于0,则减1并立即返回;如果值等于0,则调用的进程或线程阻塞进入睡眠,直到该值变为大于0,此时会再减1,函数随后返回。这种“测试病减1”的操作必须是原子的。
返回值:成功返回0,出错返回-1
int sem_trywait(sem_t *sem);
功能:与sem_wait()相同,只是当所测试的指定信号量是0时,并不阻塞进入睡眠,而是返回一个EAGAIN错误。
返回值:成功返回0,出错返回-1
int sem_post(sem_t *sem);
功能:把所指定的信号量值加1,然后唤醒正在等待该信号量值变为正数的任意进程或线程。
返回值:成功返回0,出错返回-1
int sem_getvalue(sem_t *sem, int *valp);
功能:获取指定信号量的当前值存入valp指针中,如果信号量已上锁,则获取值为0或某个负数,绝对值是等待该信号量解锁的线程数。
返回值:成功返回0,出错返回-1.
int sem_int(sem_t *sem, int shared, unsigned int value);
功能:初始化Posix共享内存的无名信号量。
返回值: 出错返回-1.
参数:sem是信号量的指针;shared为0是线程共享,为1是进程共享(sem需驻留共享内存);value是初始化值。
int sem_destory(sem_t *sem);
功能:摧毁sem_init()初始化的无名信号量。
返回值:成功返回0,出错返回-1
代码举例,父子进程采用二值信号量sem_test.c:
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <semaphore.h>
- #include <fcntl.h>
- #define USE_POSIX_SEM 1
- #define MYSEM "/mysem"
- #define RUN_TIMES 5
- int main(void)
- {
- #if USE_POSIX_SEM
- sem_t *semId;
- int val;
- //sem_unlink(MYSEM);
- semId=sem_open(MYSEM,O_CREAT,0666,0);
- if(SEM_FAILED==semId)
- {
- printf("sem open failed! ");
- return 0;
- }
- sem_getvalue(semId,&val);
- printf("sem_val init=%d ",val);
- sem_post(semId);
- sem_getvalue(semId,&val);
- printf("sem_val after post=%d ",val);
- #endif
- int pid=fork();
- if (0==pid)
- {
- int i;
- #if USE_POSIX_SEM
- sem_wait(semId);
- #endif
- for(i=0;i<RUN_TIMES;i++)
- {
- printf("child running! ");
- sleep(1);
- }
- #if USE_POSIX_SEM
- sem_post(semId);
- #endif
- printf("child end ");
- exit(0);
- }
- else if (pid>0)
- {
- int i;
- #if USE_POSIX_SEM
- sem_wait(semId);
- #endif
- for(i=0;i<RUN_TIMES;i++)
- {
- printf("parent running! ");
- sleep(1);
- }
- #if USE_POSIX_SEM
- sem_post(semId);
- #endif
- printf("parent end ");
- }
- waitpid(pid,NULL,0);
- printf("progam finished ");
- #if USE_POSIX_SEM
- sem_close(semId);
- sem_unlink(MYSEM);
- #endif
- return 0;
- }
运行结果:
$ ./a.out
sem_val init=0
sem_val after post=1
parent running!
parent running!
parent running!
parent running!
parent running!
parent end
child running!
child running!
child running!
child running!
child running!
child end
progam finished
可以看出,父进程先执行,执行5次打印后post 信号量后,子进程才执行。
如果关闭Posix 信号量,条件编译宏设为“#define USE_POSIX_SEM 0”,运行结果为:
$ ./a.out
parent running!
child running!
parent running!
child running!
parent running!
child running!
parent running!
child running!
child running!
parent running!
parent end
child end
progam finished
可以看到父子进程交替执行,存在竞争关系。
以上是关于linux进程间通信之Posix 信号量用法详解代码举例的主要内容,如果未能解决你的问题,请参考以下文章
linux进程间通信之System V共享内存详解及代码示例