说明
本文是《操作系统概念(第九版)》3.4节“进程间通信”的练习。
进程间通信主要由两种模型:
- 共享内存
- 消息传递
本文使用共享内存的方式实现进程间的通信
创建消息生产者
创建生产者的主要操作包括:
- 定义共享内存的大小、名称,以及通信消息的具体message内容
- 定义共享内存的对象和内存映射文件指针
- 用shm_open()方法,实例化共享内存对象(其参数包括共享内存名称和对象权限等)
- 用ftruncate()方法,配置共享内存对象的大小
- 用mmap()方法,创建内存映射文件,以便包含共享内存对象,它返回一个指向内存映射文件的指针,可用其访问共享内存对象
- 最后,对共享内存的写入,是通过调用sprintf()方法和向内存映射文件指针写入格式化字符串实现(每次写入之后,都要用所写字节的数量递增指针)
创建生产者的详细代码如下,可以新建一个producer.c文件,然后将代码拷贝进去:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>int main() {/* the size of shared memory object */const int SIZE = 4096;/* name of the shared memory object */const char *name = "OS";/* strings written to the shared memory */const char *message_0 = "Hello";const char *message_1 = "World!";/* shared memory file descriptor */int shm_fd;/* pointer to shared memory object */void *ptr;/* create the shared memory object */shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);/* configure the size of the shared memory object */ftruncate(shm_fd, SIZE);/* memory map the shared memory object */ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);/* write to the shared memory object */sprintf(ptr, "%s", message_0);ptr += strlen(message_0);sprintf(ptr, "%s", message_1);ptr += strlen(message_1);printf("Written done!");return 0;
}
创建消息消费者
创建消费者的代码和创建消费者的代码有一些类似的地方,但是也有一些区别:
- 不需要创建一个共享内存对象,而是通过名称去打开一个共享内存对象
- 访问内存对象之后,调用了shm_unlink()方法移除了共享内存段
创建消费者的详细代码如下,可以新建一个consumer.c文件,然后将下列代码拷贝进去:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>int main(){/* the size of shared memory object */const int SIZE = 4096;/* name of the shared memory object */const char *name = "OS";/* shared memory file descriptor */int shm_fd;/* pointer to shared memory object */void *ptr;/* open the shared memory object */shm_fd = shm_open(name, O_RDONLY, 0666);/* memory map the shared memory object */ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);/* read from the shared memory object */printf("%s", (char *)ptr);/* remove the shared memroy object */shm_unlink(name);printf("\n");printf("Read done!\n");return 0;
}
编译和运行
接下来是编译两个c文件,然后执行生产者代码,最后执行消费者代码
# 编译生产者代码
gcc -o producer producer.c -lrt## 编译消费者代码
gcc -o consumer consumer.c -lrt ## 执行生产者代码
./producer## 执行消费者代码
./consumer
最终的执行效果如下:
报错处理
致命错误:stlib.h:没有那个文件或目录
如果有下面的报错,那么是因为引用的文件名称错误,正确的应该是 #include <stdlib.h>
(我看到的书上少了一个‘d’)
producer.c:6:10: 致命错误:sys/stath:没有那个文件或目录#include <sys/stath>^~~~~~~~~~~
编译中断。
错误:‘O_RDRW’ undeclared (first use in this function); did you mean ‘O_RDWR’?
如果是下面的报错,则应该将O_RDRW
改成O_RDWR
producer.c:27:36: 错误:‘O_RDRW’ undeclared (first use in this function); did you mean ‘O_RDWR’?shm_fd = shm_open(name, O_CREAT | O_RDRW, 0666);^~~~~~O_RDWR
producer.c:27:36: 附注:每个未声明的标识符在其出现的函数内只报告一次
‘PROT_WRITE’ undeclared, ‘MAP_SHARED’未声明
以下报错,需要新增两个文件引用:
#include <sys/mman.h>
#include <unistd.h>
producer.c:33:22: 错误:‘PROT_WRITE’ undeclared (first use in this function); did you mean ‘S_IWRITE’?ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);^~~~~~~~~~S_IWRITE
producer.c:33:34: 错误:‘MAP_SHARED’未声明(在此函数内第一次使用)ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);^~~~~~~~~~
对‘shm_open’未定义的引用
解决办法: 在编译命令最后加 -lrt
/tmp/ccnkitBK.o:在函数‘main’中:
producer.c:(.text+0x39):对‘shm_open’未定义的引用
collect2: 错误:ld 返回 1