阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

进程间通信如何加锁

83次阅读
没有评论

共计 2950 个字符,预计需要花费 8 分钟才能阅读完成。

导读 进程间通信有一种 [共享内存] 方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?

进程间通信如何加锁

关于进程间的通信方式估计大多数人都知道,这也是常见的面试八股文之一。

个人认为这种面试题没什么意义,无非就是答几个关键词而已,更深入的可能面试官和面试者都不太了解。

关于进程间通信方式和优缺点我之前在【这篇文章】中有过介绍,感兴趣的可以移步去看哈。

进程间通信有一种 [共享内存] 方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?

我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?

我找到了两种方法,信号量和互斥锁。

直接给大家贴代码吧,首先是信号量方式:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

constexpr int kMappingSize = 4096;

void sem() {
    const char* mapname = "/mapname";
    int mapfd = shm_open(mapname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    MEOW_DEFER {if (mapfd > 0) {close(mapfd);
            mapfd = 0;
        }
        shm_unlink(mapname);
    };

    if (mapfd == -1) {perror("shm_open failed \n");
        exit(EXIT_FAILURE);
    }

    if (ftruncate(mapfd, kMappingSize) == -1) {perror("ftruncate failed \n");
        exit(EXIT_FAILURE);
    }

    void* sp = mmap(nullptr, kMappingSize, PROT_READ | PROT_WRITE, MAP_SHARED, mapfd, 0);
    if (!sp) {perror("mmap failed \n");
        exit(EXIT_FAILURE);
    }

    sem_t* mutex = (sem_t*)sp;

    if (sem_init(mutex, 1, 1) != 0) {perror("sem_init failed \n");
        exit(EXIT_FAILURE);
    }

    MEOW_DEFER {sem_destroy(mutex); };

    int* num = (int*)((char*)sp + sizeof(sem_t));
    int cid, proc_count = 0, max_proc_count = 8;
    for (int i = 0; i 

代码中的 MEOW_DEFER 我在之前的 RAII 相关文章中介绍过,它内部的函数会在生命周期结束后触发。它的核心函数其实就是下面这四个:

int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_post(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_destroy(sem_t *sem);

具体含义大家应该看名字就知道,这里的重点就是 sem_init 中的 pshared 参数,该参数为 1 表示可在进程间共享,为 0 表示只在进程内部共享。

第二种方式是使用锁,即 pthread_mutex_t,可是 pthread_mutex 不是用作线程间数据竞争的吗,怎么能用在进程间呢?

我也是最近才知道,可以给它配置一个属性,示例代码如下:

pthread_mutex_t* mutex;
pthread_mutexattr_t mutexattr;

pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutexattr);

它的默认属性是进程内私有,但是如果给它配置成 PTHREAD_PROCESS_SHARED,它就可以用在进程间通信中。

完整代码如下:

void func() {
    const char* mapname = "/mapname";
    int mapfd = shm_open(mapname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    MEOW_DEFER {if (mapfd > 0) {close(mapfd);
            mapfd = 0;
        }
        shm_unlink(mapname);
    };

    if (mapfd == -1) {perror("shm_open failed \n");
        exit(EXIT_FAILURE);
    }

    if (ftruncate(mapfd, kMappingSize) == -1) {perror("ftruncate failed \n");
        exit(EXIT_FAILURE);
    }

    void* sp = mmap(nullptr, kMappingSize, PROT_READ | PROT_WRITE, MAP_SHARED, mapfd, 0);
    if (!sp) {perror("mmap failed \n");
        exit(EXIT_FAILURE);
    }

    pthread_mutex_t* mutex = (pthread_mutex_t*)sp;
    pthread_mutexattr_t mutexattr;

    pthread_mutexattr_init(&mutexattr);
    pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(mutex, &mutexattr);

    MEOW_DEFER {pthread_mutexattr_destroy(&mutexattr);
        pthread_mutex_destroy(mutex);
    };

    int* num = (int*)((char*)sp + sizeof(pthread_mutex_t));
    int cid, proc_count = 0, max_proc_count = 8;
    for (int i = 0; i 

我想这两种方式应该可以满足我们日常开发过程中的大多数需求。

锁的方式介绍完之后,可能很多朋友自然就会想到原子变量,这块我也搜索了一下。但是也不太确定 C ++ 标准中的 atomic 是否在进程间通信中有作用,不过看样子 boost 中的 atomic 是可以用在进程间通信中的。

其实在研究这个问题的过程中,还找到了一些很多解决办法,包括:

    Disabling Interrupts
    Lock Variables
    Strict Alternation
    Peterson's Solution
    The TSL Instruction
    Sleep and Wakeup
    Semaphores
    Mutexes
    Monitors
    Message Passing
    Barriers

这里就不过多介绍啦,大家感兴趣的可以自行查阅资料哈。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计2950字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中