Linux系統編程(三)進程間的通信
- 一、為什么需要進程之間的通信(IPC)?
- 二、管道
- 1.概念
- 2.特質
- 3.原理
- 4.局限性
- 5.代碼
- 2.讀入數據
- 三、共享存儲映射
- 注意事項
- 父子進程通信
一、為什么需要進程之間的通信(IPC)?
當我們編碼時會發現我們使用全局變量并不能在父子進程之間使用,這是為什么呢?是因為進程與進程之間是相互獨立,當我們在主進程當中修改那個全局變量的時候,子進程的并不會變,因為兩者用戶空間的那塊地址是不一樣的。這時候我們引入了IPC,它是在內核創建了一個緩沖區,進程通過這個緩沖區實現進程之間的通信。
二、管道
1.概念
管道是一種最基本的IPC機制,作用于有血緣關系的進程之間,完成數據傳遞。調用pipe系統函數即可創建一個管道。
2.特質
1.管道的本質是一個偽文件,不占用磁盤資源
2.由兩個文件描述符引用,一個表示讀端,一個表示寫段
3.數據從管道寫段流入,讀端流出
3.原理
管道內核使用環形隊列機制,借助內核緩沖區(4k)實現
4.局限性
1.數據不能自己讀自己寫
2.數據一旦被讀走,便不在管道中存在,不可重復讀取
3.由于管道采用半雙工通信方式。數據只能一個方向上流動
4.只能在由公共祖先的進程間使用管道
5.代碼
代碼如下(示例):
#include <cstdio>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>int main()
{pid_t pid;int fd[2];int ret=pipe(fd);if (ret == -1){perror("pipe error:");exit(1);}pid = fork();if(pid==-1){ perror("pipe error:");exit(1);}else if (pid == 0) //子進程{sleep(1);close(fd[1]);char buf[1024];ret=read(fd[0], buf, sizeof(buf));if (ret == 0){printf("-----------\n");}write(STDOUT_FILENO,buf,ret);}else{close(fd[0]);char* str = "hello";write(fd[1], "hello pipe\n", strlen("hello pipe\n"));wait(NULL);}return 0;
}
2.讀入數據
代碼如下(示例):
data = pd.read_csv('https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())
該處使用的url網絡請求的數據。
三、共享存儲映射
注意事項
1.創建映射區的過程中,隱含著一次對映射文件的讀操作。
2. 當MAP_SHARED時,要求:映射區的權限應 <=文件打開的權限(出于對映射區的保護)。而MAP_PRIVATE則無所謂,因為mmap中的權限是對內存的限制。
3. 映射區的釋放與文件關閉無關。只要映射建立成功,文件可以立即關閉。
4. 特別注意,當映射文件大小為0時,不能創建映射區。所以:用于映射的文件必須要有實際大小!! mmap使用時常常會出現總線錯誤,通常是由于共享文件存儲空間大小引起的。
5. munmap傳入的地址一定是mmap的返回地址。堅決杜絕指針++操作。
6. 如果文件偏移量必須為4K的整數倍
7. mmap創建映射區出錯概率非常高,一定要檢查返回值,確保映射區建立成功再進行后續操作。
父子進程通信
```csharp
#include <cstdio>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>int main()
{//實現父子進程之間的通信int* p;int var = 100;pid_t pid;int fd = open("temp",O_CREAT|O_RDWR,0644);if (fd < 0 ){perror("open error:");exit(1);}//unlink("temp");ftruncate(fd,4);p=(int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if (p == MAP_FAILED){perror("mmap error:");exit(1);}//關閉文件close(fd);//創建子線程pid = fork();if (pid == 0){*p = 2000;var = 1000;printf("child,p = %d,var = %d\n",*p,var);}else if(pid > 0){sleep(1);printf("parent,p = %d,var = %d\n", *p, var);wait(NULL);//釋放映射區int ret = munmap(p,4);if (ret == -1){perror("munmap error:");exit(1);}}return 0;
}