简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
本篇目的:理解IPC通信消息队列、管道、socket两次内存拷贝与共享内存一次内存拷贝。
1. 两次内存拷贝的IPC方式:
管道(Pipe): 当一个进程向管道中写入数据时,数据首先会被拷贝到内核缓冲区,然后当另一个进程从管道中读取数据时,数据会从内核缓冲区拷贝到该进程的内存空间。这就是两次内存拷贝。
消息队列(Message Queue): 消息队列的工作方式与管道类似,数据在发送和接收时都需要经过内核缓冲区,因此也需要两次内存拷贝。
套接字(Socket): 套接字在发送和接收数据时,数据也需要经过内核缓冥区,因此也需要两次内存拷贝。
2. 一次内存拷贝的IPC方式:
3.总结
一次内存拷贝:
一次内存拷贝是指数据在用户空间和内核空间之间只进行了一次拷贝。在Linux和Android中,使用共享内存(shared memory)实现IPC通信是一种一次内存拷贝的方式。共享内存允许多个进程共享同一块物理内存,因此数据被写入内核空间后,其他进程可以直接在内存中读取数据,避免了多次拷贝的开销。
两次内存拷贝:
两次内存拷贝指数据在用户空间和内核空间之间进行了两次拷贝。在Linux和Android中,使用Socket、管道(pipe)和消息队列(message queue)进行IPC通信会涉及两次内存拷贝。
#include
#include
#include
int main() {
key_t key = ftok("/tmp", 'S');
int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
char *data = (char*)shmat(shmid, nullptr, 0);
std::string message = "Hello, IPC using shared memory!";
std::memcpy(data, message.c_str(), message.size());
shmdt(data);
shmctl(shmid, IPC_RMID, nullptr);
return 0;
}
// 服务器端
#include
#include
#include
int main() {
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
// 绑定和监听
int client_sock = accept(server_sock, nullptr, nullptr);
std::string message = "Hello, IPC using sockets!";
send(client_sock, message.c_str(), message.size(), 0);
close(client_sock);
close(server_sock);
return 0;
}
// 客户端
#include
#include
#include
int main() {
int client_sock = socket(AF_INET, SOCK_STREAM, 0);
// 连接服务器
char buffer[1024];
recv(client_sock, buffer, sizeof(buffer), 0);
std::cout << "Message received from server: " << buffer << std::endl;
close(client_sock);
return 0;
}
#include
#include
#include
int main() {
int pipe_fds[2];
if (pipe(pipe_fds) == -1) {
std::cerr << "Failed to create pipe" << std::endl;
return 1;
}
const char* message = "Hello, IPC using pipes!";
const size_t len = strlen(message);
if (write(pipe_fds[1], message, len) != static_cast<ssize_t>(len)) {
std::cerr << "Failed to write to pipe" << std::endl;
return 1;
}
char buffer[64];
ssize_t bytes_read = read(pipe_fds[0], buffer, sizeof(buffer));
if (bytes_read == -1) {
std::cerr << "Failed to read from pipe" << std::endl;
return 1;
}
std::cout << "Message read from pipe: " << std::string(buffer, bytes_read) << std::endl;
close(pipe_fds[0]);
close(pipe_fds[1]);
return 0;
}
#include
#include
#include
struct Message {
long type;
char text[100];
};
int main() {
key_t key = ftok("/tmp", 'Q');
int msgid = msgget(key, 0666 | IPC_CREAT);
Message message;
message.type = 1;
std::strcpy(message.text, "Hello, IPC using message queues!");
msgsnd(msgid, &message, sizeof(message.text), 0);
msgrcv(msgid, &message, sizeof(message.text), 1, 0);
std::cout << "Message received from message queue: " << message.text << std::endl;
msgctl(msgid, IPC_RMID, nullptr);
return 0;
}
#include
#include
#include
#include
#include
#include
int main() {
key_t key = ftok("/tmp", 'S');
int semid = semget(key, 1, IPC_CREAT | 0666);
if (semid == -1) {
std::cerr << "Failed to create semaphore" << std::endl;
return 1;
}
sembuf acquire = {0, -1, SEM_UNDO};
sembuf release = {0, 1, SEM_UNDO};
if (semop(semid, &acquire, 1) == -1) {
std::cerr << "Failed to acquire semaphore" << std::endl;
return 1;
}
// Critical section - perform operations that require exclusive access
std::string message = "Hello, IPC using semaphores!";
// Perform operations on the shared resource
if (semop(semid, &release, 1) == -1) {
std::cerr << "Failed to release semaphore" << std::endl;
return 1;
}
return 0;
}