基于内存的posix信号量用法

这篇博客介绍了POSIX信号量的两种形式,包括基于文件系统和基于共享内存。在文件系统中,通常使用O_CREAT|O_RDWR标志创建信号量,并在程序退出时删除。PV操作用于管理共享内存,文中提供了发送和接收进程的简单示例。对于基于共享内存的信号量,强调了内存管理的注意事项,如避免重复初始化和复制信号量,以及正确释放资源的重要性。
摘要由CSDN通过智能技术生成

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值