基于内存的posix信号量用法

来源:互联网 发布:天刀捏脸数据女听风 编辑:程序博客网 时间:2024/06/18 18:35

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 oprationint 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;}