使用mmap和posix semaphores做进程间通信与同步

来源:互联网 发布:php 打开文件 编辑:程序博客网 时间:2024/06/16 10:13

为什么要使用mmap进行IPC呢,个人总结有三点:

  1. 接口简单好用
  2. 多进程操作同一文件的时候使用mmap维护一下读写信息的meta数据非常方便
  3. 方便在非亲属进程间同步时使用

为什么要用posix semaphore进程同步呢,个人总结有三点:

  1. 接口简单好用
  2. 效率高,在Linux3.2.0开销只有0.41个Clock(而XSI semaphore有7.33)
  3. 方便在非亲属进程间同步时使用
为什么要两个结合起来用呢,因为我的应用场景是:两个没有亲戚关系的进程,同时读写一个meta数据,既需要IPC也需要同步,由于没有亲戚关系所以要使用named mmap存放posix semaphore的信号量指针(sem_t*,如果使用unamed semaphore的话),在创建mmap的时候需要设置flag为MAP_SHARED(如果还设置了MAP_ANONYMOUS则顾名思义是unamed mmap一般是在有亲戚关系进程间使用,或者同一进程的线程中使用),设置成MAP_SHARED之后可以认为是立即写回,也就是说对内存的操作等效于直接操作文件。使用named mmap的时候需要先创建一个文件,然后在使用mmap,第一次mmap之前需要设置文件大小,不然在第一次引用该mmap指针的时候会出现错误(这里我踩过坑,而且文件是否可读可写与mmap的时候最好一致),在下面的代码中会有详细注释。关于mmap的接口可以参考APUE,下面代码中也会。


posix semaphore有两种使用方式,一种是named semaphore另一种就是unnamed semaphore,它们创建与销毁接口不一样,关于posix semaphore的接口可以参考APUE,然后这里和这里都非常详细介绍了命名posix semaphore和内存中非命名posix semaphore的使用方法。

named semaphore使用的时候需要相关进程都使用同一名字,那各个毫无亲戚关系的进程这么知道使用改名字打了哪个信号量文件呢?在/dev/shm中会存放一个sem file,比如如果使用"mutex"作为semaphore名字的时候,在/dev/shm会创建一个sem.mutex的文件,其它进程在使用"mutex"这个名字打开semaphore的时候会使用该文件,这样各个进程就知道了是同一semaphore了,代码中有注释。

unnamed semaphore则可以通过类似于共享内存的方式存放semaphore变量(sem_t),这里我们本身维护了一个meta被mmap了被进程共享,那可以把这个变量放在meta的数据结构中(封装),这样既可以IPC也可以同步了。

下面两段代码第一段是named semaphore & mmap,第二段是unamed semaphore & mmap,为了简化就是两个进程读写一个cnt,posix semaphore需要加-lpthread。

-----------------------------------------named semaphore-----------------------------------------------

#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <semaphore.h>#include <fcntl.h>#include <sys/mman.h>typedef struct _meta_t {    int _cnt;} meta_t;int main(){    // create a semaphore file named sem.mutex in /dev/shm    // use 0-1 name semaphore so set the value as 1    sem_t* mutex = sem_open("mutex", O_CREAT, 0664, 1);    if (!mutex) {        perror("open mutex failed");        abort();    }    // create a file at first before create a named mmap    FILE* f = fopen("./log.meta","w+");    if (!f) {        fprintf(stderr,"file open failed\n");        abort();     }    // "If don't set the output file's size the call mmap for the output is    // successful but the first reference to the associated memeory region    // generates a SIGBUS signal" --- APUE c14.8 p530    ftruncate(fileno(f), sizeof(meta_t));    meta_t* ptr = mmap(NULL,sizeof(meta_t), PROT_WRITE, MAP_SHARED, fileno(f), 0);    if (ptr == MAP_FAILED) {        fprintf(stderr,"mmap failed\n");        fclose(f);        abort();    }    ptr->_cnt = 0;    int cnt = 10;    while (cnt--) {        sem_wait(mutex);        printf("a : %d\n", ptr->_cnt);        ++ptr->_cnt;        printf("a : %d\n", ptr->_cnt);        sem_post(mutex);        sleep(1);    }    sem_close(mutex);    sem_unlink("mutex");    munmap(f,sizeof(meta_t));    close(f);    return 0;}/////////////////////////////////////////////#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <semaphore.h>#include <fcntl.h>#include <sys/mman.h>typedef struct _meta_t {    int _cnt;} meta_t;int main(){    // create a semaphore file named sem.mutex in /dev/shm    // use 0-1 name semaphore so set the value as 1    sem_t* mutex = sem_open("mutex", O_CREAT, 0664, 1);    if (!mutex) {        perror("open mutex failed");        abort();    }    // create a file at first before create a named mmap    FILE* f = fopen("./log.meta","a+");    if (!f) {        fprintf(stderr,"file open failed\n");        abort();     }    // "If don't set the output file's size the call mmap for the output is    // successful but the first reference to the associated memeory region    // generates a SIGBUS signal" --- APUE c14.8 p530    // ftruncate(fileno(f), sizeof(meta_t)); no need in this process    meta_t* ptr = mmap(NULL,sizeof(meta_t), PROT_WRITE, MAP_SHARED, fileno(f), 0);    if (ptr == MAP_FAILED) {        fprintf(stderr,"mmap failed\n");        fclose(f);        abort();    }    int cnt = 10;    while (cnt--) {        sem_wait(mutex);        printf("b : %d\n", ptr->_cnt);        --ptr->_cnt;        printf("b : %d\n", ptr->_cnt);        sem_post(mutex);        sleep(1);    }    sem_close(mutex);    sem_unlink("mutex");    munmap(f,sizeof(meta_t));    close(f);    return 0;}


-------------------------------unnamed semaphore------------------------------------------

#include<stdio.h>#include<semaphore.h>#include<fcntl.h>#include<sys/mman.h>typedef struct _meta_t {    int _cnt;    sem_t _mutex;} meta_t, *ptr_meta_t;int main(){    FILE* f = fopen("./log.meta","w+");    if (!f) {        fprintf(stderr,"file open failed\n");    }    // If don't set the output file's size the call mmap for the output is    // successful but the first reference to the associated memeory region    // generates a SIGBUS signal    ftruncate(fileno(f), sizeof(meta_t));    meta_t* ptr = mmap(NULL,sizeof(meta_t), PROT_WRITE, MAP_SHARED, fileno(f), 0);    if (ptr == MAP_FAILED) {        fprintf(stderr,"mmap failed\n");        return -1;    }    ptr->_cnt = 0;    int ret = sem_init(&ptr->_mutex, 1, 1);    if (ret) {        fprintf(stderr,"init semaphore failed\n");    }    int cnt = 10;    while (cnt--) {        sem_wait(&ptr->_mutex);        printf("c : %d\n", ptr->_cnt);        (ptr->_cnt) += 1;        printf("c : %d\n", ptr->_cnt);        sem_post(&ptr->_mutex);        sleep(1);    }    sem_destroy(&ptr->_mutex);    munmap(f,sizeof(meta_t));    close(f);    return 0;}/////////////////////////////////////////////////////#include<stdio.h>#include<semaphore.h>#include<fcntl.h>#include<sys/mman.h>typedef struct _meta_t {    int _cnt;    sem_t _mutex;} meta_t, *ptr_meta_t;int main(){    FILE* f = fopen("./log.meta","r+"); // do not use w+ in this process    if (!f) {        fprintf(stderr,"file open failed\n");    }    // If don't set the output file's size the call mmap for the output is    // successful but the first reference to the associated memeory region    // generates a SIGBUS signal    // ftruncate(fileno(f), sizeof(meta_t)) no need in this process    meta_t* ptr = mmap(NULL,sizeof(meta_t), PROT_WRITE, MAP_SHARED, fileno(f), 0);    if (ptr == MAP_FAILED) {        fprintf(stderr,"mmap failed\n");        return -1;    }    int ret = sem_init(&ptr->_mutex, 1, 1);    if (ret) {        fprintf(stderr,"init semaphore failed\n");    }    int cnt = 10;    while (cnt--) {        sem_wait(&ptr->_mutex);        printf("d : %d\n", ptr->_cnt);        (ptr->_cnt) -= 1;        printf("d : %d\n", ptr->_cnt);        sem_post(&ptr->_mutex);        sleep(1);    }    sem_destroy(&ptr->_mutex);    munmap(f,sizeof(meta_t));    close(f);    return 0;}







0 0
原创粉丝点击