一、使用场景:
在项目中要用进程来进行代码并行运算,节省大量的时间,子进程的代码一定要与主代码之间尽量独立:
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;
}