日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下进程间通信方式之管道、信号、共享内存、消息队列、信号量、套接字

發布時間:2025/3/21 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下进程间通信方式之管道、信号、共享内存、消息队列、信号量、套接字 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
/* 1,進程間通信 (IPC ) Inter-Process Communication比較好理解概念的就是進程間通信就是在不同進程之間傳播或交換信息。2,linux下IPC機制的分類:管道、信號、共享內存、消息隊列、信號量、套接字3,這篇主要說說管道:本質是文件,其他理論什么的網上已經有一大堆了,我就只寫一點用法吧。3.1 特點1)管道是最古老的IPC,但目前很少使用2)以文件做交互的媒介,管道分為有名管道和無名管道3)歷史上的管道通常是指半雙工管道3.2 管道:有兩種形式,命令行和非命令行(1)命令行:mkfifo testfifoecho "testfifo" >fifocat fifo(2)非命令行:這里又分有名管道和無名管道編程模型:進程A創建管道(mkfifo) -> 進程A寫打開管道(open) -> 進程B讀打開管道(open) -> 進程A開始往管道里寫數據(write) ->進程B從管道中讀數據(read) -> 進程A關閉管道(close) -> 進程B關閉管道(close) -> 刪除管道(unlink) */ //有名管道(實例): //進程A:#include<sys/stat.h> #include<fcntl.h> #include<stdio.h>#define PIPENAME "pipetest"int main() {// 創建管道if(mkfifo(PIPENAME, 0666) < 0){perror("mkfifo");return -1;}// 寫打開管道 int fd = open(PIPENAME, O_WRONLY);if(-1 == fd){perror("open");return -1;}unlink(PIPENAME);int i = 0;for(i = 0; i < 10; i++){write(fd, &i, sizeof(i));printf("%d\n", i);sleep(1); // 這個是以秒為單位掛起}// 關閉管道close(fd);return 0;}//進程B:#include<sys/stat.h> #include<fcntl.h> #include<stdio.h>#define PIPENAME "pipetest"int main() {// 讀打開管道int fd = open(PIPENAME, O_RDONLY);if(-1 == fd){perror("open");return -1;}int num = 0;int i = 0;for(i = 0; i < 10; i++){read(fd, &num, sizeof(int));printf("%d\n", num);fflush(stdout); // 強制刷新輸出緩沖區}printf("\n");close(fd);return 0;}/* 一,消息隊列1,概念:“消息隊列”是在消息的傳輸過程中保存消息的容器2,消息隊列就是一個消息的鏈表。可以把消息看作一個記錄,具有特定的格式以及特定的優先級。對消息隊列有寫權限的進程可以向消息隊列中按照一定的規則添加新消息;對消息隊列有讀權限的進程則可以從消息隊列中讀走消息。消息隊列是隨內核持續的。3,編程注意事項:使用時先把數據封裝成消息,把消息存入隊列編程步驟: 具體函數的用法可以用man手冊查看(強力推薦)(1)ftok()生產key(2)使用msgget( ) 創建/獲取消息隊列,返回值是隊列標識符(3)使用msgsnd( ) 發送消息使用msgrcv( ) 接收消息(4)使用msgctl( ) 刪除消息隊列 4,實例:sendmsg.c 用來發送消息的 */ // sendmsg.c#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #include<string.h>struct my_msg {int mtype; // 消息類型char buf[256]; }msg1, msg2;int main() {key_t key = ftok("./", 88);int msgid = msgget(key, 0666|IPC_CREAT);if(-1 == msgid){perror("msgget failed!!!");exit(1);}msg1.mtype = 2;strcpy(msg1.buf, "hello, msg2");msgsnd(msgid, &msg1, sizeof(msg1), 0); // 阻塞// msgsnd(msgid, &msg1, sizeof(msg1), IPC_NOWAIT); // 非阻塞msg2.mtype = 1;strcpy(msg2.buf, "hello, msg1");msgsnd(msgid, &msg2, sizeof(msg2), 0); // 阻塞printf("消息發送完成,按回車銷毀消息隊列\n");getchar();if(-1 == shmctl(msgid, IPC_RMID, NULL)){perror("shmctl failed");exit(2);}return 0; }//recvmsg.c 用來接收消息的// recvmsg.c#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #include<string.h>struct my_msg {int mtype; // 消息類型char buf[256]; }msg;int main() {key_t key = ftok("./", 88);// 獲取消息隊列int msgid = msgget(key, 0);if(-1 == msgid){perror("msgget failed!!!");exit(1);}int res = msgrcv(msgid, &msg, sizeof(msg),2, // 取消息類型為2的消息0);printf("類型:%d, 內容:%s\n", msg.mtype, msg.buf);printf("消息接收完成,按回車銷毀消息隊列\n");getchar();if(-1 == shmctl(msgid, IPC_RMID, NULL)){perror("shmctl failed");exit(2);}return 0; }/* 一,共享內存 內核管理一片物理內存,允許不同的進程同時映射,多個進程可以映射同一塊內存,被多個進程同時映射的物理內存,即共享內存。 映射物理內存叫掛接,用完以后解除映射叫脫接。1,共享內存的特點:優點:是最快的IPC。缺點:要編程者自己實現對共享內存互斥訪問。如何實現?2,編程模型:具體函數的用法可以用man手冊查看(強力推薦)進程A: writeshm.c1) 獲得key, ftok()2) 使用key來創建一個共享內存 shmget()3) 映射共享內存(得到虛擬地址), shmat()4) 使用共享內存, 往共享內存中寫入數據5) 解除映射 shmdt()6) 如果共享內存不再使用,可以使用shmctl()銷毀共享內存進程B: readshm.c 1) 獲得key, ftok() 2) 使用key來獲得一個共享內存 shmget() 3) 映射共享內存(得到虛擬地址), shmat() 4) 使用共享內存, 讀取共享內存中的數據 5) 解除映射 shmdt() 3,實例*///進程A: // writeshm.c#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h>int main() {// 生成一個keykey_t key = ftok("./", 66);// 創建共享內存,返回一個idint shmid = shmget(key, 8, IPC_CREAT|0666|IPC_EXCL);if(-1 == shmid){perror("shmget failed");exit(1);}// 映射共享內存,得到虛擬地址void *p = shmat(shmid, 0, 0);if((void*)-1 == p){perror("shmat failed");exit(2);}// 寫共享內存int *pp = p;*pp = 0x12345678;*(pp + 1) = 0xffffffff;// 解除映射if(-1 == shmdt(p)){perror("shmdt failed");exit(3);}printf("解除映射成功,點擊回車銷毀共享內存\n");getchar();// 銷毀共享內存if(-1 == shmctl(shmid, IPC_RMID, NULL)){perror("shmctl failed");exit(4);}return 0; }//進程B:// readshm.c#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h>int main() {// 生成一個keykey_t key = ftok("./", 66);// 獲取共享內存,返回一個idint shmid = shmget(key, 0, 0);if(-1 == shmid){perror("shmget failed");exit(1);}// 映射共享內存,得到虛擬地址void *p = shmat(shmid, 0, 0);if((void*)-1 == p){perror("shmat failed");exit(2);}// 讀共享內存int x = *(int *)p;int y = *((int *)p + 1);printf("從共享內存中都取了:0x%x 和 0x%x \n", x, y);// 解除映射if(-1 == shmdt(p)){perror("shmdt failed");exit(3);}return 0; }/* 一、信號量1,信號量本質是一個計數器,控制訪問共享資源的最大并行進程總數。(和信號有很大的區別)2,信號量的使用主要是用來保護共享資源,使得資源在一個時刻只有一個進程(線程)所擁有。 信號量的值為正的時候,說明它空閑。所測試的線程可以鎖定而使用它。若為0,說明它被占用,測試的線程要進入睡眠隊列中,等待被喚醒。3,信號量分類:Linux提供兩種信號量: (1) 內核信號量,由內核控制路徑使用 (2) 用戶態進程使用的信號量,這種信號量又分為POSIX信號量和SYSTEMV信號量。 POSIX信號量又分為有名信號量和無名信號量。 有名信號量,其值保存在文件中, 所以它可以用于線程也可以用于進程間的同步。無名信號量,其值保存在內存中。干貨來源: http://blog.csdn.net/qinxiongxu/article/details/78305374,最簡單的信號量是只能取0和1的變量,這也是信號量最常見的一種形式,叫做二進制信號量。而可以取多個正整數的信號量被稱為通用信號量。這里主要討論二進制信號量。5,使用方法使用時給其一個初始值,假如該資源允許同時兩個進程使用,初始值就設置為2,有一個進程使用該資源計數-1(原子操作),有一個進程放棄使用該資源計數+1(原子操作)。如果計數為0,不允許新的進程來訪問資源,新的進程阻塞等待,直到計數重新大于0解除阻塞。 如果有多個資源需要控制訪問,就需要多個信號量,把多個信號量存入數組中,這個數組就叫信號量集。二,編程實現參考: http://blog.csdn.net/ljianhui/article/details/10243617 其實就是用這篇博客的。這里用的是二進制信號量,初始值是1,最多允許1個進程獲取信號量。 這個例子采用兩個相同的程序往終端輸出字符,根據命令行參數加以區分。*/#include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<sys/sem.h>union semun {int val;struct semid_ds *buf;unsigned short *arry; };static int sem_id = 0; static int set_semvalue(); static void del_semvalue(); static int semaphore_p(); static int semaphore_v();int main(int argc, char **argv) {char message = 'x';int i = 0;// 創建信號量sem_id = semget((key_t)1234, 1, 0666|IPC_CREAT);if(argc > 1){// 程序第一次調用,初始化信號量if(!set_semvalue()){fprintf(stderr, "Failed Init semaphore\n");exit(EXIT_FAILURE);}// 設置輸出到屏幕中的信息message = argv[1][0];sleep(2);}for(i = 0; i < 10; i++){if(!semaphore_p()) // 進入臨界區{exit(EXIT_FAILURE);}printf("%c", message);fflush(stdout); // 清理緩沖區sleep(rand() % 3); // 休眠隨機時間printf("%c", message);fflush(stdout); if(!semaphore_v()) // 離開臨界區{exit(EXIT_FAILURE);}sleep(rand() % 2); // 休眠隨機時間}sleep(10);printf("\n %d - finished\n", getpid());if(argc > 1){sleep(3);del_semvalue();}exit(EXIT_SUCCESS); }// 初始化信號量 static int set_semvalue() {union semun sem_union;sem_union.val = 1;if(-1 == semctl(sem_id, 0, SETVAL, sem_union)){return 0;}return 1; }// 刪除信號量 static void del_semvalue() {union semun sem_union;if(-1 == semctl(sem_id, 0, IPC_RMID, sem_union)){fprintf(stderr, "Failed delete semphore\n");} }// 對信號量-1操作,即等待P(sv) static int semaphore_p() {struct sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_op = -1; // P()sem_b.sem_flg = SEM_UNDO;if(-1 == semop(sem_id, &sem_b, 1)){fprintf(stderr, "Failed semaphore_p()\n");return 0;}return 1; }// 釋放操作, +1, 發送信號V(sv) static int semaphore_v() {struct sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_op = 1; // P()sem_b.sem_flg = SEM_UNDO;if(-1 == semop(sem_id, &sem_b, 1)){fprintf(stderr, "Failed semaphore_v()\n");return 0;}return 1; } /* 因為每個程序都在其進入臨界區后和離開臨界區前打印一個字符,所以每個字符都應該成對出現。 一個進程在打印時,會先執行P操作,若沒有打印完,也就是沒有執行V操作。另一個進程要執行打印,也要進行P操作,這時候由于信號量的值為0,獲取信號量失敗,進程只能掛起自己。等另一個程序釋放(V操作)才能打印。 任何時刻只有一個進程得到了信號量,只有一個進程在執行打印 總結: 信號量是一個特殊的變量,程序對其訪問都是原子操作,且只允許對它進行等待(即P(信號變量))和發送(即V(信號變量))信息操作。 我們通常通過信號來解決多個進程對同一資源的訪問競爭的問題,使在任一時刻只能有一個執行線程訪問代碼的臨界區域, 也可以說它是協調進程間的對同一資源的訪問權,也就是用于同步進程的。 */

總結

以上是生活随笔為你收集整理的Linux下进程间通信方式之管道、信号、共享内存、消息队列、信号量、套接字的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。