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
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
#include
#include
#include
#include
#include
#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!\n");
return 0;
}
sem_getvalue(semId,&val);
printf("sem_val init=%d\n",val);
sem_post(semId);
sem_getvalue(semId,&val);
printf("sem_val after post=%d\n",val);
#endif
int pid=fork();
if (0==pid)
{
int i;
#if USE_POSIX_SEM
sem_wait(semId);
#endif
for(i=0;i
{
printf("child running!\n");
sleep(1);
}
#if USE_POSIX_SEM
sem_post(semId);
#endif
printf("child end\n");
exit(0);
}
else if (pid>0)
{
int i;
#if USE_POSIX_SEM
sem_wait(semId);
#endif
for(i=0;i
{
printf("parent running!\n");
sleep(1);
}
#if USE_POSIX_SEM
sem_post(semId);
#endif
printf("parent end\n");
}
waitpid(pid,NULL,0);
printf("progam finished\n");
#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
可以看到父子进程交替执行,存在竞争关系。