posix信号量的两种形式
基于文件系统
不打算详细讲细节,提供两种模板,简单的用法
#include <semaphore.h>
sem_t* sem_open(const char*name,int oflag,.../*mode_t mode,unsigned int value*/)
oflag参数我一般指定O_CREAT|O_RDWR,因为一般不保存信号量,毕竟总觉得这东西会一直占系统资源,所以我创建时指定O_CREAT,意思就是如果不存在和这个信号量,则创建并初始化它,若存在则为这个信号量重新赋值。一般程序退出时删除它。
mode参数可以参考man 2 open。我一般指定#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH),方便好用。
int sem_close(semt_t *sem);
注意,close一个信号量并没释放它的资源,posix信号量至少是随内核持续的,close只是“扯断这个信号量和进程的联系”。我们要真的删除某个信号量时,应该用
int sem_unlink(sem_t *sem);
删除仅当没有任何进程还打开这个信号量时成功
PV操作
int sem_wait(sem_t *sem);//p opration
int sem_post(sem_t *sem);//v opration
这就是操作系统课上讲的PV操作
demo
两个进程,mmap共享一个内存,通过信号量来管理这个共享内存。一个进程从stdin收取字符串,并写入共享内存,然后V信号量
另一个进程P信号量,拿走字符串,v信号量。输出到stdout。
发送程序输入exit,可以将接收程序终止
注意 编译时要链接 lrt或者lpthread
Send.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex = sem_open("wudi_sem",O_CREAT|O_RDWR,FILE_MODE,0);
int fd = open("0xabc",O_CREAT|O_RDWR,FILE_MODE);
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
write(fd,buf,1024);
close(fd);
while(scanf("%s",buf)!=EOF)
{
memcpy(sharedFile,buf,128);
sem_post(mutex);
}
sem_unlink("wudi_sem");
printf("unlink mutex\n");
return 0;
}
Recv.c
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex = sem_open("wudi_sem",O_RDWR);
int fd = open("0xabc",O_RDWR);
if(fd<0)
{
perror("open:");
exit(-1);
}
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
close(fd);
while(1)
{
sem_wait(mutex);
memcpy(buf,sharedFile,128);
if(strcmp(buf,"exit")==0)
{
printf("ready to exit\n");
break;
}
printf("get msg>> %s\n",buf);
}
sem_unlink("wudi_sem");
printf("unlink mutex\n");
return 0;
}
注意以上两个程序并未十分安全的处理临界区,send方对共享内存的写其实并不安全,因为可能recv方正在读取那个数据,正确的做法应该是将共享内存做成一个队列,这样写的位置和读的位置就能避免冲突。但此处仅作演示用,而且从stdin收东西其实很慢的。。。。。
基于共享内存的信号量
int sem_init(sem_t *sem,int shared,int value);
int sem_destroy(sem_t *sem);
注意:
- sem的内存由调用者自己分配,并得确保这个内存一直存在
- 不要重复对一个信号量调用sem_init(),其结果是未定义的
- 不要copy信号量,使用copy后的信号量的副本,其结果是未定义的
- sem_init失败时返回-1,但成功时并不返回0
- 就算是在stack空间上分配的空间,也要在不使用时,调用sem_destroy释放资源
其中 shared 参数 指示是否在进程间共享
demo
将上一个例子改成基于共享内存的信号量
Send.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex; //= sem_open("wudi_sem",O_CREAT|O_RDWR,FILE_MODE,0);
char *dataStart;
int fd = open("0xabc",O_CREAT|O_RDWR,FILE_MODE);
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
write(fd,buf,1024);
close(fd);
mutex = (sem_t*)sharedFile;
if(sem_init(mutex,1,0) < 0)
{
perror("mutex init");
exit(-1);
}
dataStart = (char*)sharedFile + sizeof(sem_t);
while(scanf("%s",buf)!=EOF)
{
memcpy(dataStart,buf,128);
sem_post(mutex);
}
sem_destroy(mutex);
printf("exit\n");
return 0;
}
Recv.c
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex; //= sem_open("wudi_sem",O_RDWR);
char *dataStart;
int fd = open("0xabc",O_RDWR);
if(fd<0)
{
perror("open:");
exit(-1);
}
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
close(fd);
mutex = (sem_t*)sharedFile;
//make sure there exist a sempahore at the start of sharedFile
dataStart = (char*)sharedFile + sizeof(sem_t);
while(1)
{
sem_wait(mutex);
memcpy(buf,dataStart,128);
if(strcmp(buf,"exit")==0)
{
printf("ready to exit\n");
break;
}
printf("get msg>> %s\n",buf);
}
sem_destroy(mutex);
printf("exit\n");
return 0;
}