匿名管道
这里利用的是读时共享的策略,因为只有读操作时,子进程是共享父进程的资源,那么我们进行这样的操作
- 创建子进程之前,创建一个管道
- 子、父进程往管道写内容,子、父进程从管道读内容,这样就实现了信息传递
这里我有个疑问,写时拷贝,为什么管道不会复制? 找了很多资料,无果,暂时搁浅吧。
- 方法1 - linux命令
ls | wc -l
# ls 显示目录下的文件,包含目录
# | 管道符号
# wc -l 统计行号
# ls 显示文件列表
- 方法2 - 代码
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
int main(){
// pipe two ends
int pipefd[2];
// create pipe
if(pipe(pipefd) == -1){
perror("pipe");
exit(0);
}
int ret = fork();
if(ret == 0){
// son process
// wait father write data
sleep(1);
char buf [1024];
// read data from pipe write to buf, and return the len of read data
int len = read(pipefd[0], &buf, 1024);
printf("%d %s\n", len, buf);
close(pipefd[0]);
} else if(ret == -1){
perror("fork");
exit(0);
} else {
// father
// write data
write(pipefd[1], "hello tiffany!\n", 16);
close(pipefd[1]);
}
}
有名管道
匿名管道仅仅局限于有亲属关系的进程当中。
在任意两个进程间进行管道通信,需要使用有名管道。
- 方法1 - 命令行
mkfifo afifo
# 不知道怎么使用,基于命令行
- 方法2 - 代码
// create fifo
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
int ret = mkfifo("afifo", 0664);
if(ret == -1){
perror("mkfifo");
exit(0);
}
}
// write to pipe
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(){
int fd = open("afifo", O_WRONLY);
if(fd == -1){
perror("fifo");
exit(0);
}
char buf[1024];
sprintf(buf, "hello ethan\n");
write(fd, buf, strlen(buf));
printf("write: %s\n", buf);
return 0;
}
// read from fifo
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(){
int fd = open("afifo", O_RDONLY);
if(fd == -1){
perror("fifo");
exit(0);
}
char readBuff[1024];
int len = read(fd, readBuff, 1024);
printf("read: %s\n", readBuff);
return 0;
}
tips: when we only open fifo by O_WRONLY, the fifo will be blocked, untill the one process open it by O_RDONLY or O_RDWR.
so,
- run create process, fifo named afifo will be created;
- run write process, the process will be blocked;
- run read process, write and read will be succsessfully completed.
匿名内存映射
原理,将一个文件映射到一块内存,相当于开辟了一块内存,两个进程先后的访问这块内存,相当于把这块内存当作中转站,即可实现共享。匿名,内存的首地址在创建子进程之前,所以子进程能共享该内存指针
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <wait.h>
int main(){
// open a file to mmap
int fd = open("test.txt", O_RDWR);
int size = lseek(fd, 0, SEEK_END);
// create a memory map area
void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(ptr == MAP_FAILED){
perror("mmap");
exit(0);
}
pid_t pid = fork();
if(pid > 0){
wait(NULL);// wait for recycle process by blocked
char buf [1024];
strcpy(buf, (char *)ptr);
printf("read data: %s\n", buf);
} else if(pid == 0){
// child process
strcpy((char *)ptr, "nihao nina tiffany\n");
}
// close memory map area
munmap(ptr, size);
}
内存映射
// write.cpp
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(){
// 1. open a file
int fd = open("test.txt", O_RDWR);
// 2. mmap
void* ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
getchar();
// 3. write data
strcpy((char *)ptr, "hello nihao");
// 4. unmap and close fd
munmap(ptr, 1024);
close(fd);
return 0;
}
// read.cpp
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(){
// 1. open a file
int fd = open("test.txt", O_RDWR);
// 2. mmap
void* ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// 3. read data
printf("%s", (char *)ptr);
getchar();
printf("%s", (char *)ptr);
// 4. unmap and close fd
munmap(ptr, 1024);
close(fd);
return 0;
}
共享内存
// write
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(){
// 1. create a shm
int shmid = shmget(100, 1024, IPC_CREAT | 0664);
// 2. let the shm associate with current process
void* ptr = shmat(shmid, NULL, 0);
// 3. write data
const char* str = "hello ethan";
memcpy(ptr, str, strlen(str) + 1);
printf("%s", (char *)ptr);
getchar();
// 4. detach the association
shmdt(ptr);
// 5. delete the shm
shmctl(shmid, IPC_RMID, NULL);
}
// read
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(){
// 1. create a shm
int shmid = shmget(100, 1024, IPC_CREAT);
// 2. let the shm associate with current process
void* ptr = shmat(shmid, NULL, 0);
// 3. read data
getchar();
printf("%s", (char*)ptr);
// 4. detach the association
shmdt(ptr);
// 5. delete the shm
shmctl(shmid, IPC_RMID, NULL);
}
内存映射与共享内存比较
- 内存映射无大小限制,共享内存大小小于主存的大小
- 内存映射与实际的文件关联,共享内存无关联
- 当程序异常终止,内存映射的文件可能保存在文件中, 当共享内存无了
- 内存映射可能涉及到磁盘读写,速度慢于共享内存