一、进程间如何通信
中心思想:需要一个额外的空间,一个进程往里写,另一个进程往外读。
- 空间可以是磁盘或内存。
- 空间里读写时,属于生产者-消费者模型,保证同步问题。(同步问题,操作系统内部已经实现,使用者直接使用即可)
1. 管道
简介
磁盘中存储的是文件,所以将磁盘作为空间时,这种方法叫做管道(pipe),
匿名管道:
- 创建匿名管道文件,文件描述符fd[0]和fd[1]
- fd[0]用于读文件内容,fd[1]用于向文件写内容
- 只能用于父子进程间通信
- 只能单向传输
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/wait.h>
int main()
{
char *message = "hello world";
char buf[100];
int pipe_fd[2];
if (pipe(pipe_fd) < 0) { //创建管道
perror("pipe ");
exit(EXIT_FAILURE);
}
if (fork() == 0) //child
{
printf("wait read\n");
read(pipe_fd[0], buf, sizeof(buf)); // 管道空阻塞
printf("buf = %s\n", buf);
close(pipe_fd[0]);
} else {
sleep(1);
write(pipe_fd[1], message, strlen(message)+1);
printf("write over\n");
close(pipe_fd[1]);
wait(NULL); //父进程等待子进程结束,防止子进程变成孤儿
}
return 0;
}
# 结果
wait read
write over
buf = hello world
命名管道
用于非亲缘关系间的通信。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int ret;
ret = mkfifo("/tmp/fif", 0777);
if (ret < 0) {
perror("mkfifo");
exit(EXIT_FAILURE);
}
int fd = open("/tmp/fif", O_RDWR);
if (fd < 0) {
perror("open error");
exit(EXIT_FAILURE);
}
char buf[100];
read(fd, buf, 100);
printf("buf = %s\n", buf);
close(fd);
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main()
{
char buf[100];
int fd = open("/tmp/fif", O_RDWR);
if (fd < 0) {
perror("open error");
exit(EXIT_FAILURE);
}
write(fd, "hello", sizeof("hello"));
close(fd);
return 0;
}
2. 共享内存(POSIX标准下)
使用步骤
- 在内存中申请空间,shm-open,得到文件描述符
- 设置文件大小,ftruncate
- 映射文件到内存,mmap
- 从内存中拷贝内容
- 关闭文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main()
{
const char *sham_name = "my_shm";
char data[] = "Hi, Shard memory";
int shm_fd = shm_open(sham_name, O_CREAT|O_RDWR, 0777);
if (shm_fd < 0) {
printf("shm_fd error\n");
}
ftruncate(shm_fd, 4096);
void *ptr = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);
printf("ptr = %p\n", ptr);
memcpy(ptr, data, sizeof(data)+1);
printf("ptr = %s\n", (char *)ptr);
close(shm_fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main()
{
int shm_fd;
const char *sham_name = "my_shm";
shm_fd = shm_open(sham_name, O_RDONLY, 0777);
if (shm_fd < 0) {
perror("shm_open error");
exit(EXIT_FAILURE);
}
void * m_ptr = mmap(0, 4096, PROT_READ, MAP_SHARED, shm_fd, 0);
if (m_ptr == MAP_FAILED) {
perror("m_ptr error");
exit(EXIT_FAILURE);
}
printf("shared mem contents %s\n", (char *)m_ptr);
close(shm_fd);
shm_unlink(sham_name);
return 0;
}
运行结果
shared mem contents Hi, Shard memory
共享内存实现机制
3. 消息队列
使用方法:
mqd_t mq = mq_open("/my_queue", O_CREATE|O_RDWR, 0644, &attr);
mq_send(mq, buffer, msg_len, 0);// 最后一个参数是优先级
mq_receive(mq, buffer, MAX_SIZE, NULL);// 最后一个参数是优先级