c++代码实现同一台主机两个步伐实实际时通信
对于历程间通信方式有很多种,对于本机两个步伐中可以实时通信那么应该选择哪个呢?很多人最快想到的就是socket通信。
套接字适用于跨网络的历程间通信,具有网络透明性、机动性和安全性高的优点,但性能开销较大,延迟较高!
共享内存适用于同一台呆板上的历程间通信,具有高性能、低延迟和高吞吐量的优点,但需要手动管理同步机制,安全性较低。以是我们优先使用共享内存来实现,在智能驾驶等工业场景中使用非常多。
共享内存实现
历程A:
- #include <cstring>
- #include <iostream>
- #include <sys/shm.h>
- #include <thread>
- #include <unistd.h>
- #define SHM_KEY_A 12345
- #define SHM_KEY_B 67890
- #define SHM_SIZE 1024
- void send_messages(char* send_data)
- {
- std::string message;
- while (std::getline(std::cin, message)) {
- if (message == "exit") {
- break;
- }
- strncpy(send_data, message.c_str(), SHM_SIZE - 1);
- send_data[SHM_SIZE - 1] = '\0';
- while (std::strlen(send_data) > 0) {
- usleep(100000); // 等待 100 毫秒
- }
- }
- }
- void receive_messages(char* recv_data)
- {
- while (true) {
- while (std::strlen(recv_data) == 0) {
- usleep(100000); // 等待 100 毫秒
- }
- std::cout << "Received message: " << recv_data << std::endl;
- std::memset(recv_data, 0, SHM_SIZE);
- }
- }
- int main()
- {
- // 创建共享内存A(用于接收消息)
- int shmid_a = shmget(SHM_KEY_A, SHM_SIZE, 0666);
- if (shmid_a == -1) {
- std::cerr << "Failed to get shared memory A" << std::endl;
- return 1;
- }
- // 创建共享内存B(用于发送消息)
- int shmid_b = shmget(SHM_KEY_B, SHM_SIZE, 0666);
- if (shmid_b == -1) {
- std::cerr << "Failed to get shared memory B" << std::endl;
- return 1;
- }
- // 将共享内存连接到当前进程
- char* recv_data = (char*)shmat(shmid_a, nullptr, 0);
- char* send_data = (char*)shmat(shmid_b, nullptr, 0);
- if (recv_data == (char*)-1 || send_data == (char*)-1) {
- std::cerr << "Failed to attach shared memory" << std::endl;
- return 1;
- }
- std::thread sender(send_messages, send_data);
- std::thread receiver(receive_messages, recv_data);
- sender.join();
- receiver.join();
- // 清理共享内存
- shmdt(recv_data);
- shmdt(send_data);
- shmctl(shmid_a, IPC_RMID, nullptr);
- shmctl(shmid_b, IPC_RMID, nullptr);
- return 0;
- }
复制代码 历程B:
- #include <cstring>
- #include <iostream>
- #include <sys/shm.h>
- #include <thread>
- #include <unistd.h>
- #define SHM_KEY_A 12345
- #define SHM_KEY_B 67890
- #define SHM_SIZE 1024
- void send_messages(char* send_data)
- {
- std::string message;
- while (std::getline(std::cin, message)) {
- if (message == "exit") {
- break;
- }
- strncpy(send_data, message.c_str(), SHM_SIZE - 1);
- send_data[SHM_SIZE - 1] = '\0';
- while (std::strlen(send_data) > 0) {
- usleep(100000); // 等待 100 毫秒
- }
- }
- }
- void receive_messages(char* recv_data)
- {
- while (true) {
- while (std::strlen(recv_data) == 0) {
- usleep(100000); // 等待 100 毫秒
- }
- std::cout << "Received message: " << recv_data << std::endl;
- std::memset(recv_data, 0, SHM_SIZE);
- }
- }
- int main()
- {
- // 获取共享内存A(用于发送消息)
- int shmid_a = shmget(SHM_KEY_A, SHM_SIZE, IPC_CREAT | 0666);
- if (shmid_a == -1) {
- std::cerr << "Failed to create shared memory A" << std::endl;
- return 1;
- }
- // 获取共享内存B(用于接收消息)
- int shmid_b = shmget(SHM_KEY_B, SHM_SIZE, IPC_CREAT | 0666);
- if (shmid_b == -1) {
- std::cerr << "Failed to create shared memory B" << std::endl;
- return 1;
- }
- // 将共享内存连接到当前进程
- char* send_data = (char*)shmat(shmid_a, nullptr, 0);
- char* recv_data = (char*)shmat(shmid_b, nullptr, 0);
- if (send_data == (char*)-1 || recv_data == (char*)-1) {
- std::cerr << "Failed to attach shared memory" << std::endl;
- return 1;
- }
- std::thread sender(send_messages, send_data);
- std::thread receiver(receive_messages, recv_data);
- sender.join();
- receiver.join();
- // 清理共享内存
- shmdt(send_data);
- shmdt(recv_data);
- shmctl(shmid_a, IPC_RMID, nullptr);
- shmctl(shmid_b, IPC_RMID, nullptr);
- return 0;
- }
复制代码 代码简洁比较容易。有些捞仔可能会问了,除了共享内存另有没有其它方式呢?有!当然有,只不过性能不如共享内存啦。
命名管道实现
历程A:
- #include <fstream>
- #include <iostream>
- #include <sys/stat.h>
- #include <thread>
- #include <unistd.h>
- #define PIPE_NAME_A "pipe_a"
- #define PIPE_NAME_B "pipe_b"
- void send_messages(const std::string& pipe_name)
- {
- std::ofstream pipe(pipe_name);
- if (!pipe) {
- std::cerr << "Failed to open named pipe for writing" << std::endl;
- return;
- }
- std::cout << "Enter messages to send (type 'exit' to quit):" << std::endl;
- while (true) {
- std::string message;
- std::getline(std::cin, message);
- if (message == "exit") {
- break;
- }
- pipe << message << std::endl;
- pipe.flush();
- }
- }
- void receive_messages(const std::string& pipe_name)
- {
- std::ifstream pipe(pipe_name);
- if (!pipe) {
- std::cerr << "Failed to open named pipe for reading" << std::endl;
- return;
- }
- std::cout << "Waiting for messages..." << std::endl;
- while (true) {
- std::string message;
- std::getline(pipe, message);
- // 处理程序在没有数据时不会频繁地检查管道,从而节省CPU资源,同时保持对新数据的响应
- if (pipe.eof()) {
- sleep(1);
- pipe.clear();
- pipe.seekg(0, std::ios::end);
- } else {
- std::cout << "Received message: " << message << std::endl;
- }
- }
- }
- int main()
- {
- // 创建命名管道
- if (mkfifo(PIPE_NAME_A, 0666) == -1) {
- std::cerr << "Failed to create named pipe A" << std::endl;
- return 1;
- }
- if (mkfifo(PIPE_NAME_B, 0666) == -1) {
- std::cerr << "Failed to create named pipe B" << std::endl;
- return 1;
- }
- std::thread sender(send_messages, PIPE_NAME_A);
- std::thread receiver(receive_messages, PIPE_NAME_B);
- sender.join();
- receiver.join();
- return 0;
- }
复制代码 历程B:
- #include <fstream>
- #include <iostream>
- #include <sys/stat.h>
- #include <thread>
- #include <unistd.h>
- #define PIPE_NAME_A "pipe_a"
- #define PIPE_NAME_B "pipe_b"
- void send_messages(const std::string& pipe_name)
- {
- std::ofstream pipe(pipe_name);
- if (!pipe) {
- std::cerr << "Failed to open named pipe for writing" << std::endl;
- return;
- }
- std::cout << "Enter messages to send (type 'exit' to quit):" << std::endl;
- while (true) {
- std::string message;
- std::getline(std::cin, message);
- if (message == "exit") {
- break;
- }
- pipe << message << std::endl;
- pipe.flush();
- }
- }
- void receive_messages(const std::string& pipe_name)
- {
- std::ifstream pipe(pipe_name);
- if (!pipe) {
- std::cerr << "Failed to open named pipe for reading" << std::endl;
- return;
- }
- std::cout << "Waiting for messages..." << std::endl;
- while (true) {
- std::string message;
- std::getline(pipe, message);
- if (pipe.eof()) {
- sleep(1);
- pipe.clear();
- pipe.seekg(0, std::ios::end);
- } else {
- std::cout << "Received message: " << message << std::endl;
- }
- }
- }
- int main()
- {
- std::thread sender(send_messages, PIPE_NAME_B);
- std::thread receiver(receive_messages, PIPE_NAME_A);
- sender.join();
- receiver.join();
- return 0;
- }
复制代码 相对于共享内存的优缺点:
优点:
- 简单易用:命名管道的实现相对简单,得当用于简单的历程间通信。
缺点:
- 性能开销:命名管道的性能略低于共享内存,因为数据需要通过内核缓冲区传输。共享内存是所有历程间通信(IPC)机制中最快的,因为它不需要在历程之间复制数据。
- 单向通信:命名管道通常是单向的,需要两个管道实现双向通信。
还可以使用消息队列实现(本人使用的是wsl2,微软不支持,故没有代码)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |