进程间通信——共享内存,信号量,信号

进程 VS 线程通信

进程:共享内存,消息队列,管道,信号(条件变量,锁,信号量需要搭配共享内存使用);
线程:信号,条件变量,锁,信号量

代码示例

使用父子子进程交替打印进行演示

sem_init + 共享内存

重点介绍 sem_init 函数参数
int sem_init(sem_t *sem, int pshared, unsigned int value);
第一个参数sem——信号量地址
第二个参数pshared——0:进程内部通信;非0:进程间通信,必须要配合共享内存一起使用
第三个参数——指定信号量的初始值

#include <iostream>
#include <vector>
using namespace std;
#include <semaphore.h>// 信号量
#include <pthread.h>
#include <sys/ipc.h> // 共享内存
#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

// 进程间通信 —— 两个进程交替打印
// 1. sem_init + 共享内存
class Text1
{
public:
    struct SemData
    {
        int flag = 0;
        sem_t father;
    };

    const string pathname = "/tmp";
    void Main()
    {
        key_t key = ftok(pathname.c_str(),666);
        int shmid = shmget(key,sizeof(SemData),IPC_CREAT | 0666);// 创建
        if(shmid == -1){
            perror("shmget");
            exit(1);
        }
        cout << shmid << endl;
        SemData* mem = (SemData*)shmat(shmid,nullptr,0);
        if(mem == nullptr){
            perror("shmat");
            exit(2);
        }
        sem_init(&mem->father,1,1);// 进程间共享

        int pid = 0;
        if(pid = fork()){
            // 父进程
            while(1){
                sem_wait(&mem->father);
                printf("father: %d\n",mem->flag++);
                if(waitpid(pid,nullptr,WNOHANG)){
                    break;
                }
                sem_post(&mem->father);
                sleep(1);
            }
            shmdt(mem);
            shmctl(shmid,IPC_RMID,nullptr);
        }else{
            while(1){
                sem_wait(&mem->father);
                if(mem->flag > 10){
                    puts("children exit");
                    sem_post(&mem->father);
                    exit(0);
                }
                printf("children: %d\n",mem->flag++);
                sem_post(&mem->father);
                sleep(1);
                
            }
        }
    }
};
int main()
{
    Text1 test1;
    test1.Main();
    
    return 0;
}

sem_open 进程直接通信

sem_open 参数介绍
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
第一个参数:以/ 开头的文件路径在测试时发现,就算不加/并且使用不存在的路径也是可以运行的
第二个参数:打开标志——和linux中的文件标志一样
第三个参数:创建的信号量的使用权限,一般使用0666
第四个参数:信号量的数量

#include <iostream>
#include <vector>
using namespace std;
#include <semaphore.h>// 信号量
#include <pthread.h>
#include <sys/ipc.h> // 共享内存
#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

// sem_open 直接进程间通信
class Text2
{
public:
    void test()
    {
        const string path = "/tmp";
        sem_t* sem_father = sem_open(path.c_str(),O_CREAT | O_EXCL, 0644,1);

        int pid = 0;
        if(pid = fork()){
            // 父进程
            int cnt = 1;
            while(1){
                sem_wait(sem_father);
                printf("father: %d\n",cnt);
                cnt += 2;
                if(waitpid(pid,nullptr,WNOHANG)){
                    break;
                }
                sem_post(sem_father);
                sleep(1);
            }
        }else{
            int cnt = 0;
            while(1){
                sem_wait(sem_father);
                if(cnt > 10){
                    puts("children exit");
                    sem_post(sem_father);
                    exit(0);
                }
                printf("children: %d\n",cnt);
                cnt+=2;
                sem_post(sem_father);
                sleep(1);
            }
        }
    }
    void Main()
    {
        test();
    }
};
int main()
{
    Text2 test2;
    test2.Main();
    
    return 0;
}

在这里插入图片描述

信号通信

注意
SIGUSR1,SIGUSR2 是留给用户自定义行为的信号,我们这里选择SIGUSR1

// 使用信号的方式进行进程间通信
class Text3
{
public:
    // static volatile int flag;
    static volatile int flag;
    static void handle(int sig)
    {
        flag = 1;
    }
    void test()
    {
        signal(SIGUSR1,handle);
        int pid=0;
        if(pid = fork()){
            // 父进程
            while(1){
                while(!flag) {}
                flag=0;
                printf("father\n");
                if(waitpid(pid,nullptr,WNOHANG)){
                    break;
                }
                kill(pid,SIGUSR1);
                sleep(1);
            }
        }else{
            while(1){
                printf("children\n");
                kill(getppid(),SIGUSR1);
                while(!flag){}
                flag=0;

                sleep(1);
            }
        }
    }
    void Main()
    {
        test();
    }
};
volatile int Text3::flag = 0;

int main()
{
    Text3 test3;
    test3.Main();
    
    return 0;
}

在这里插入图片描述

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 13:00:02       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 13:00:02       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 13:00:02       45 阅读
  4. Python语言-面向对象

    2024-07-21 13:00:02       55 阅读

热门阅读

  1. from lxml import etree 的功能

    2024-07-21 13:00:02       17 阅读
  2. (四)js前端开发中设计模式之工厂方法模式

    2024-07-21 13:00:02       21 阅读
  3. 【web]-反序列化-easy ? not easy

    2024-07-21 13:00:02       18 阅读
  4. php编译安装

    2024-07-21 13:00:02       18 阅读
  5. centos 网卡创建vlan接口

    2024-07-21 13:00:02       15 阅读
  6. 【头歌】 HBase 伪分布式环境搭建 答案

    2024-07-21 13:00:02       15 阅读
  7. ubuntu 挂载硬盘,raspberry pi 树莓派,jetson

    2024-07-21 13:00:02       20 阅读
  8. PCIe总线-RK3588 PCIe驱动设备树介绍(九)

    2024-07-21 13:00:02       14 阅读
  9. 我的创作纪念日——365天

    2024-07-21 13:00:02       18 阅读
  10. 掌握Perl的魔法:深入探索钩子(Hook)机制

    2024-07-21 13:00:02       18 阅读
  11. 【AI原理解析】—粒子群(PSO)原理

    2024-07-21 13:00:02       15 阅读