百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

linux|进程间通信如何加锁

liebian365 2025-01-17 12:11 18 浏览 0 评论

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

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

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

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

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

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

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

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

#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 < max_proc_count; ++i) {
        cid = fork();
        if (cid == -1) {
            perror("fork failed \n");
            continue;
        }
        if (cid == 0) {
            sem_wait(mutex);
            (*num)++;
            printf("process %d : %d \n", getpid(), *num);
            sem_post(mutex);

            if (munmap(sp, kMappingSize) == -1) {
                perror("munmap failed\n");
            }
            close(mapfd);
            exit(EXIT_SUCCESS);
        }
        ++proc_count;
    }

    int stat;
    while (proc_count--) {
        cid = wait(&stat);
        if (cid == -1) {
            perror("wait failed \n");
            break;
        }
    }

    printf("ok \n");
}

代码中的MEOW_DEFER,它内部的函数会在生命周期结束后触发。它的核心函数其实就是下面这四个:

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,它就可以用在进程间通信中。

相关视频推荐

360度无死角讲解进程管理,调度器的5种实现

Linux进程间通信-信号量、消息队列和共享内存

学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

完整代码如下:

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 < max_proc_count; ++i) {
        cid = fork();
        if (cid == -1) {
            perror("fork failed \n");
            continue;
        }
        if (cid == 0) {
            pthread_mutex_lock(mutex);
            (*num)++;
            printf("process %d : %d \n", getpid(), *num);
            pthread_mutex_unlock(mutex);

            if (munmap(sp, kMappingSize) == -1) {
                perror("munmap failed\n");
            }
            close(mapfd);
            exit(EXIT_SUCCESS);
        }
        ++proc_count;
    }

    int stat;
    while (proc_count--) {
        cid = wait(&stat);
        if (cid == -1) {
            perror("wait failed \n");
            break;
        }
    }

    printf("ok \n");
}

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

锁的方式介绍完之后,可能很多朋友自然就会想到原子变量,这块我也搜索了一下。但是也不太确定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

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

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: