进程之间的数据共享

一、使用场景:

        在项目中要用进程来进行代码并行运算,节省大量的时间,子进程的代码一定要与主代码之间尽量独立:

        1、不要牵涉保存或者读取同样的文件,因为这样会两个子进程会同时修改,导致程序出错;

        2、关于深度模型预测这块代码,若是子进程里面用到模型预测,一定需要模型在子进程中进行声明与初始化,否则代码出错,同时模型预测会混乱。

        3、主代码与子进程之间共享变量,方式有很多种:管道、消息队列、共享内存和套接字等方式,共享变量若是string类型,则需要将其转化为char []形式,因为string空间是不固定的,无法解析其大小;

二、共享变量方式:

1、使用管道(Pipe):

#include <iostream>
#include <vector>
#include <sys/types.h>
#include <unistd.h>

struct Data
{
    int value;
    // 添加其他需要的字段
};


int main()
{

    int pipefd[2];
    if (pipe(pipefd) == -1) 
    {
        std::cerr << "Failed to create pipe" << std::endl;
        return 1;
    }

    pid_t pid = fork();
    if (pid == 0)
    {
        // 子进程写入数据到管道
        close(pipefd[0]); // 关闭读端
        std::vector<Data> result;

        // 假设在子进程中产生了一些结果
        Data data1 {1};
        Data data2 {2};
        result.push_back(data1);
        result.push_back(data2);
        write(pipefd[1], result.data(), result.size() * sizeof(Data));
        close(pipefd[1]);
        return 0;
    }

    // 父进程从管道读取子进程的结果
    close(pipefd[1]); // 关闭写端
    std::vector<Data> result;
    Data buffer;
    while (read(pipefd[0], &buffer, sizeof(Data)) > 0) 
    {
        result.push_back(buffer);
    }
    close(pipefd[0]);
    
    // 处理子进程的结果
    for (const auto& data : result)
    {
        std::cout << "Value: " << data.value << std::endl;
    }
    return 0;
}

2、使用消息队列:

#include <iostream>
#include <vector>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct Data
{
    long mtype;
    int value;
    // 添加其他需要的字段
};


int main()
{
    key_t key = ftok(".", 'm');
    if (key == -1) 
    {
        std::cerr << "Failed to generate key for message queue" << std::endl;
        return 1;
    }

    int msgid = msgget(key, IPC_CREAT | 0666);
    if (msgid == -1) 
    {
        std::cerr << "Failed to create message queue" << std::endl;
        return 1;
    }

    pid_t pid = fork();
    if (pid == 0) 
    {
        // 子进程发送数据到消息队列
        std::vector<Data> result;

        // 假设在子进程中产生了一些结果
        Data data1 {1, 10};
        Data data2 {1, 20};
        result.push_back(data1);
        result.push_back(data2);

        for (const auto& data : result) 
        {
            msgsnd(msgid, &data, sizeof(Data), IPC_NOWAIT);
        }
        return 0;
    }

    // 父进程从消息队列接收子进程的结果
    std::vector<Data> result;
    Data buffer;

    while (msgrcv(msgid, &buffer, sizeof(Data), 1, IPC_NOWAIT) != -1)
    {
        result.push_back(buffer);
    }

    // 处理子进程的结果
    for (const auto& data : result)
    {
        std::cout << "Value: " << data.value << std::endl;
    }
    msgctl(msgid, IPC_RMID, nullptr);
    
    return 0;
}

3、使用共享内存(Shared Memory):

#include <iostream>
#include <vector>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

struct Data 
{
    int value;
    // 添加其他需要的字段
};


int main()
{
    key_t key = ftok(".", 's');
    if (key == -1) 
    {
    std::cerr << "Failed to generate key for shared memory" << std::endl;
    return 1;
    }

    int shmid = shmget(key, sizeof(std::vector<Data>), IPC_CREAT | 0666);
    if (shmid == -1) 
    {
        std::cerr << "Failed to create shared memory" << std::endl;
        return 1;
    }

    void* shmptr = shmat(shmid, nullptr, 0);
    std::vector<Data>* result = static_cast<std::vector<Data>*>(shmptr);

    pid_t pid = fork();
    if (pid == 0)
    {
        // 子进程在共享内存中写入数据
        std::vector<Data> data;
        // 假设在子进程中产生了一些结果
        Data data1 {1};
        Data data2 {2};
        data.push_back(data1);
        data.push_back(data2);
        *result = data;
        shmdt(shmptr);
        return 0;
     }

    // 父进程从共享内存中读取子进程的结果
    while (result->empty())
    {
        // 等待子进程写入数据
    }

    // 处理子进程的结果
    for (const auto& data : *result) 
    {
        std::cout << "Value: " << data.value << std::endl;
    }
    shmctl(shmid, IPC_RMID, nullptr);

    return 0;
}

注意事项:

shmget()函数: 创建共享内存;

shmat()函数:启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间;

shmdt()函数 : 该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用;

shmctl()函数:用来控制共享内存;

4、使用套接字(Socket):

#include <iostream>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

struct Data
{
    int value;
    // 添加其他需要的字段
};


int main()
{
    int sockfd[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1) 
    {
        std::cerr << "Failed to create socket pair" << std::endl;
        return 1;
    }

    pid_t pid = fork();
    if (pid == 0) 
    {
        // 子进程通过套接字发送数据
        close(sockfd[0]); // 关闭父进程端口

        std::vector<Data> result;
        // 假设在子进程中产生了一些结果
        Data data1 {1};
        Data data2 {2};
        result.push_back(data1);
        result.push_back(data2);
        write(sockfd[1], result.data(), result.size() * sizeof(Data));
        close(sockfd[1]);
        return 0;
    }

    // 父进程通过套接字接收子进程的结果
    close(sockfd[1]); // 关闭子进程端口
    std::vector<Data> result;

    Data buffer;
    while (read(sockfd[0], &buffer, sizeof(Data)) > 0) 
    {
        result.push_back(buffer);
    }
    close(sockfd[0]);
    
    // 处理子进程的结果
    for (const auto& data : result) 
    {
        std::cout << "Value: " << data.value << std::endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐凡星

你的鼓励将是我的动力;

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值