操作系统实验——进程通信(FIFO、shared memory)
共享内存
编译指令:
gcc shared_memory.cpp -I/usr/local/include/ -L/usr/local/lib -lrt -o shared_mem
代码:
/** * Sample code for sharing memory between processes * Two processes will iteratively increase a counter which values stored in a shared memory * */ #include <stdio.h> #include <unistd.h> // for fork() #include <sys/mman.h> // for shared memory created #include <sys/stat.h> // for mode constants #include <fcntl.h> // for O_* constant #define SHARED_OBJ_NAME "/somename" // shared data struct struct message { int pid; int counter; }; bool write_message(int pid, int value) { int shmFd = shm_open(SHARED_OBJ_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); ftruncate(shmFd, sizeof(message)); message *msg_ptr = (message*)mmap(NULL, sizeof(message), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0); printf("Process %d: Increase the counter.\n", pid); msg_ptr->pid = pid; msg_ptr->counter = value; munmap(msg_ptr, sizeof(message)); // remember to close to not hit an error of // opening too many files close(shmFd); return true; } bool read_message(int curr_pid, int &curr_value) { int shmFd = shm_open(SHARED_OBJ_NAME, O_RDWR, S_IRUSR | S_IWUSR); ftruncate(shmFd, sizeof(message)); message *msg_ptr = (message*)mmap(NULL, sizeof(message), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0); if (msg_ptr->pid == curr_pid) { printf("Process %d: No new msg available.\n", curr_pid); return false; } else { printf("Process %d: Receive %d from PID %d.\n", curr_pid, msg_ptr->counter, msg_ptr->pid); curr_value = msg_ptr->counter; munmap(msg_ptr, sizeof(message)); } close(shmFd); return true; } int main(int argc, char **argv) { printf("Init the initial value.\n"); write_message(-1, 0); // create a child process by calling folk, // it returns a non-zero pid for parent process and 0 for child process created pid_t pid = fork(); //--- PARENT PROCESS if (pid != 0) { for (int i = 0; i < 5; i++) { int value; // only write message if reading sucessfully if (read_message(pid, value)) write_message(pid, ++value); sleep(0.1); } } //--- CHILD PROCESS else { for (int j = 0; j < 5; j++) { int value; if (read_message(pid, value)) write_message(pid, ++value); sleep(0.1); } } printf("=========== End of process %d\n", pid); //shm_unlink(SHARED_OBJ_NAME); return 0; }
运行结果:
Init the initial value. Process -1: Increase the counter. Process 440735: Receive 0 from PID -1. Process 440735: Increase the counter. Process 440735: Receive 2 from PID 0. Process 440735: Increase the counter. Process 440735: No new msg available. Process 440735: No new msg available. Process 440735: Receive 4 from PID 0. Process 440735: Increase the counter. =========== End of process 440735 Init the initial value. Process -1: Increase the counter. Process 0: Receive 1 from PID 440735. Process 0: Increase the counter. Process 0: Receive 3 from PID 440735. Process 0: Increase the counter. Process 0: Receive 5 from PID 440735. Process 0: Increase the counter. Process 0: No new msg available. Process 0: No new msg available. =========== End of process 0
FIFO
编译指令:
gcc fifo.cpp -I/usr/local/include/ -L/usr/local/lib -lrt -o fifo
/** * Example for using named pipe for communicating between processes * This demo is for a unidirectional named pipe which transfer data in one direction */ #include "csapp.h" #define NAMED_PIPE "/var/lock/pipename" // shared data struct struct message { int pid; int counter; }; int main(int argc, char **argv) { // create the named pipe (fifo) with permission int ret = mkfifo(NAMED_PIPE, 0666); if (ret < 0) printf("Error when creating FIFO. %s\n", strerror(errno)); // create a child process by calling folk, // it returns a non-zero pid for parent process and 0 for child process created pid_t pid = fork(); //--- the parent process will write to the pipe only if (pid != 0) { int fd = open(NAMED_PIPE, O_WRONLY); for (int i = 0; i < 5; i++) { message msg; msg.pid = pid; msg.counter = i; printf("Process %d: Write %d.\n", pid, i); ret = write(fd, &msg, sizeof(msg)); if (ret < 0) printf("Process %d: Error while writing message. %s\n", pid, strerror(errno)); sleep(0.1); } close(fd); } //-- child process will read only else { int fd = open(NAMED_PIPE, O_RDONLY); for (int i = 0; i < 5; i++) { message msg; ret = read(fd, &msg, sizeof(msg)); if (ret < 0) printf("Process %d: Error while reading message. %s\n", pid, strerror(errno)); printf("Process %d: Received value %d from the parent process %d.\n", pid, msg.counter, msg.pid); sleep(0.1); } close(fd); } unlink(NAMED_PIPE); return 0; }
运行结果:
Process 424351: Write 0. Process 424351: Write 1. Process 424351: Write 2. Process 424351: Write 3. Process 424351: Write 4. Process 0: Received value 0 from the parent process 424351. Process 0: Received value 1 from the parent process 424351. Process 0: Received value 2 from the parent process 424351. Process 0: Received value 3 from the parent process 424351. Process 0: Received value 4 from the parent process 424351.
消息队列
使用消息队列的步骤,定义消息结构->创建消息队列->通过消息队列向进程A发送消息->通过消息队列接收进程A的消息。
每条消息都有一个标识或“类型”,以便进程可以选择适当的消息,并且进程必须共享一个公共“密钥”才能首先获得对队列的访问权限。
进程可以从队列发送或接收消息,队列必须通过msgget()操作初始化,发送和接收消息分别由msgsnd( )和msgrcv()函数执行。
下面的程序实现父进程和子进程之间C/S方式的通信。
#include "csapp.h" struct mesg_buffer { long mesg_type; char mesg_text[100]; } message; int main(int argc, char **argv) { pid_t pid = fork(); if (pid != 0) { key_t key; int msgid; // generate unique key key = ftok("somefile", 65); msgid = msgget(key, 0666 | IPC_CREAT); message.mesg_type = 1; printf("Insert message : "); // scanf("%s", message.mesg_text); fgets(message.mesg_text, 100, stdin); // send message msgsnd(msgid, &message, sizeof(message), 0); // display the message printf("Message sent to server : %s\n", message.mesg_text); } else { key_t key; int msgid; // generate unique key key = ftok("somefile", 65); msgid = msgget(key, 0666 | IPC_CREAT); printf("Waiting for a message from client...\n"); // receive message msgrcv(msgid, &message, sizeof(message), 1, 0); // display the message printf("Message received from client : %s \n", message.mesg_text); // to destroy the message queue ; msgctl(msgid, IPC_RMID, NULL); } return 0; }
编译、运行指令:
$ gcc msgqueue.cpp -I/usr/local/include/ -L/usr/local/lib -o msgque $ ./msgque 使用stdin输入: $ hello world!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!