文章目錄
- 共享內存
- 信號
- 管道
- 消息隊列
通信方法 | 無法介于內核態與用戶態的原因 |
管道(不包括命名管道) | 局限于父子進程間的通信。 |
消息隊列 | 在硬、軟中斷中無法無阻塞地接收數據。 |
信號量 | 無法介于內核態和用戶態使用。 |
共享內存 | 需要信號量輔助,而信號量又無法使用。 |
共享內存
共享內存是最快的進程間通訊的方式
-
原因:相對于其他幾種方式,共享內存直接在進程的虛擬地址空間進行操作,不再通過執行進入內核的系統調用來傳遞彼此的數據
-
shmget函數
功能 | 用來創建共享內存 |
---|---|
原型 | int shmget(key_t key, size_t size, int shmflg); |
參數key: | 這個共享內存段名字 |
size: | 共享內存大小 |
shmflg: | 由九個權限標志構成,它們的用法和創建文件時使用的mode模式標志是一樣的 |
返回值: | 成功返回?一個?非負整數,即該共享內存段的標識碼;失敗返回-1 |
- shmat函數
功能: | 將共享內存段連接到進程地址空間 |
---|---|
原型 | void *shmat(int shmid, const void *shmaddr, int shmflg); |
參數shmid: | 共享內存標識 |
shmaddr: | 指定連接的地址 |
shmflg: | 它的兩個可能取值是SHM_RND和SHM_RDONLY |
返回值: | 成功返回?一個指針,指向共享內存第?一個節;失敗返回-1 |
- shmctl函數
功能: | ?用于控制共享內存 |
---|---|
原型 | int shmctl(int shmid, int cmd, struct shmid_ds *buf); |
參數shmid: | 由shmget返回的共享內存標識碼 |
cmd: | 將要采取的動作(有三個可取值) |
buf: | 指向?一個保存著共享內存的模式狀態和訪問權限的數據結構 |
返回值: | 成功返回0;失敗返回-1 |
- shmdt函數
功能: | 將共享內存段與當前進程脫離 |
---|---|
原型 | int shmdt(const void *shmaddr); |
參數shmaddr: | 由shmat所返回的指針 |
返回值: | 成功返回0;失敗返回-1 |
注意: | 將共享內存段與當前進程脫離不等于刪除共享內存段 |
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>typedef struct _Teacher
{char name[64];int age;
}Teacher;int main(int argc, char *argv[])
{int ret = 0;int shmid;//創建共享內存 ,相當于打開文件,文件不存在則創建shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666); if (shmid == -1){perror("shmget err");return errno;}printf("shmid:%d \n", shmid);Teacher *p = NULL;//將共享內存段連接到進程地址空間p = shmat(shmid, NULL, 0);//第二個參數shmaddr為NULL,核心自動選擇一個地址if (p == (void *)-1 ){perror("shmget err");return errno;}strcpy(p->name, "aaaa");p->age = 33;//將共享內存段與當前進程脫離shmdt(p);printf("鍵入1 刪除共享內存,其他不刪除\n");int num;scanf("%d", &num);if (num == 1){//用于控制共享內存ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID為刪除內存段if (ret < 0){perror("rmerrr\n");}} return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>typedef struct _Teacher
{char name[64];int age;
}Teacher;int main(int argc, char *argv[])
{int ret = 0;int shmid;//shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT |IPC_EXCL | 0666); //打開獲取共享內存shmid = shmget(0x2234, 0, 0); if (shmid == -1){perror("shmget err");return errno;}printf("shmid:%d \n", shmid);Teacher *p = NULL;//將共享內存段連接到進程地址空間p = shmat(shmid, NULL, 0);if (p == (void *)-1 ){perror("shmget err");return errno;}printf("name:%s\n", p->name);printf("age:%d \n", p->age);//將共享內存段與當前進程脫離shmdt(p);printf("鍵入1 程序暫停,其他退出\n");int num;scanf("%d", &num);if (num == 1){pause();} return 0;
}
選取簡單的代碼,可運行觀察效果
信號
信號量和以前的IPC通信方式不同,信號量的本質是計數器,用于多進程對共享數據對象的訪問。
在進程訪問臨界資源之前,需要測試信號量,如果為正數,則信號量-1并且進程可以進入臨界區,若為非正數,則進程掛起放入等待隊列,直至有進程退出臨界區,釋放資源并+1信號量,此時喚醒等待隊列的進程。
信號量本身就是臨界資源,所以必須是原子操作。
- 生產者消費者模型:
https://blog.csdn.net/csdn_kou/article/details/81240666
管道
單向,一端輸入,另一端輸出,先進先出FIFO。管道也是文件。管道大小4096字節。
- 特點:管道滿時,寫阻塞;空時,讀阻塞。
- 分類:普通管道(僅父子進程間通信)位于內存;命名管道位于文件系統,沒有親緣關系管道只要知道管道名也可以通訊。
- 管道是由內核管理的一個緩沖區(buffer),相當于我們放入內存中的一個紙條。管道的一端連接一個進程的輸出。這個進程會向管道中放入信息。管道的另一端連接一個進程的輸入,這個進程取出被放入管道的信息。一個緩沖區不需要很大,它被設計成為環形的數據結構,以便管道可以被循環利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會等待,直到另一端的進程取出信息。當兩個進程都終結的時候,管道也自動消失
- 匿名管道與命名管道的區別
- 匿名管道由pipe函數創建并打開。
- 命名管道由mkfifo函數創建,打開用open
- FIFO(命名管道)與pipe(匿名管道)之間唯一的區別在它們創建與打開的方式不同,一但這些工作完成之后,它們具有相同的語義。
消息隊列
消息隊列是先進先出FIFO原則
ipcs & ipcrm命令
- ipcs: 顯示IPC資源
- ipcrm: 手動刪除IPC資源