<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
無名管道只能用於親緣間程序的通訊,無名管道的大小是64K。無名管道是核心空間實現的機制。
1) Pipe()建立一個管道,這是一個單向的資料通道,可用於程序間通訊。
2)陣列pipefd用於返回兩個指向管道末端的檔案描述符。
3)Pipefd[0]指的是管道的讀端。Pipefd[1]指的是管道的寫入端,寫入管道的寫入端資料由核心進行緩衝(64k),直到從管道的讀取端讀取為止。
1.只能用於親緣間程序的通訊
2.無名管道資料半雙工的通訊的方式
單工 : A -------------->B
半雙工 : 同一時刻 A----->B B------>A
全雙工 : 同一時刻 A<---->B
3.無名管道的大小是64K
4.無名管道不能夠使用lseek函數
5.讀寫的特點
如果讀端存在寫管道:有多少寫多少,直到寫滿為止(64k)寫阻塞
如果讀端不存寫管道,管道破裂(SIGPIPE) (可以通過gdb偵錯看現象)
如果寫端存在讀管道:有多少讀多少,沒有資料的時候阻塞等待
如果寫端不存在讀管道:有多少讀多少,沒有資料的時候立即返回
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) int main(int argc, char const *argv[]) { pid_t pid; int num[2]; char buff[128] = {0}; if (pipe(num)){ ERROR("pipe error"); } if ((pid = fork()) == -1){ ERROR("fork error"); }else if(pid == 0){ close(num[0]); while (1){ memset(buff, 0, sizeof(buff)); printf("請輸入您要輸入的數值>>"); fgets(buff, sizeof(buff), stdin); buff[strlen(buff) -1] = ' '; write(num[1], buff, strlen(buff)); if (!strncmp(buff, "quit", 4)){ break; } } close(num[1]); exit(EXIT_SUCCESS); }else{ close(num[1]); while (1){ memset(buff, 0, sizeof(buff)); read(num[0], buff, sizeof(buff)); if (!strncmp(buff, "quit", 4)){ break; } printf("%sn",buff); } close(num[0]); wait(NULL); } return 0; }
1)可以用於親緣間程序的通訊,也可以用於非親緣間的程序的通訊。
2)有名管道會建立一個檔案,需要通訊的程序開啟這個檔案,產生檔案描述符後就可以通訊了,有名管道的檔案存在記憶體上。
3)有名管道的大小也是64K,也不能使用lseek函數
1.可以用於任意程序間的通訊
2.有名管道資料半雙工的通訊的方式
3.有名管道的大小是64K
4.有名管道不能夠使用lseek函數
5.讀寫的特點
如果讀端存在寫管道:有多少寫多少,直到寫滿為止(64k)寫阻塞
如果讀端不存寫管道
1.讀許可權沒有開啟,寫端在open的位置阻塞
2.讀端開啟後關閉,管道破裂(SIGPIPE) (可以通過gdb偵錯看現象)
如果寫端存在讀管道:有多少讀多少,沒有資料的時候阻塞等待
如果寫端不存在讀管道
1.寫許可權沒有開啟,讀端在open的位置阻塞
2.寫端開啟後關閉,有多少讀多少,沒有資料的時候立即返回
mkfifo檔案:
#include <stdio.h> #include <stdlib.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) int main(int argc, char const *argv[]) { if (mkfifo("./fifo",0666)){ ERROR("mkfifo error"); } //有名管道沒有阻塞,手動加一個阻塞 getchar(); system("rm ./fifo -rf"); return 0; }
write檔案:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) int main(int argc, char const *argv[]) { int fd; char buff[128] = {0}; if ((fd = open("./fifo",O_WRONLY)) == -1){ ERROR("open fifo errorn"); } while(1){ printf("input >"); fgets(buff, sizeof(buff), stdin); buff[strlen(buff) - 1] = ' '; write(fd, buff, strlen(buff)); if(!strncmp("quit",buff,4))break; } close(fd); return 0; }
read檔案:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #define ERROR(msg) do { printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); } while (0) int main(int argc, char const *argv[]) { int fd; char buff[128] = {0}; if ((fd = open("./fifo", O_RDONLY)) == -1) { ERROR("open error"); } while (1){ memset(buff, 0, sizeof(buff)); read(fd, buff, sizeof(buff)); if (!strncmp("quit",buff,4)){ break; } printf("%sn",buff); } close(fd); return 0; }
訊號是中斷的一種軟體模擬,中斷是基於硬體實現的,訊號是基於linux核心實現的。
使用者可以給程序發訊號,程序可以給程序發訊號,核心也可以給程序發訊號。程序對
訊號的處理方式有三種:捕捉,忽略,預設
int raise(int sig);
功能:給自己(程序或者執行緒)發訊號
引數:
@sig:訊號號
返回值:成功返回0,失敗返回非0
int kill(pid_t pid, int sig);
功能:給程序發訊號
引數:
@pid:程序號
@sig:訊號號
返回值:成功返回0,失敗返回-1置位錯誤碼
1.在上述的訊號中只有SIGKILL和SIGSTOP兩個訊號不能被捕捉也不能被忽略
2.SIGCHLD,當子程序結束的時候,父程序收到這個SIGCHLD的訊號
捕捉ctrl+c
#include <stdio.h> #include <signal.h> #include <stdlib.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) void handle(int num) { if (num == SIGINT){ printf("我收到一個ctrl+c的訊號n"); } } int main(int argc, char const *argv[]) { //捕捉 if (signal(SIGINT, handle) == SIG_ERR){ ERROR("register signal error"); } //忽略 if (signal(SIGINT,SIG_IGN) == SIG_ERR){ ERROR("register signal error"); } //預設 if (signal(SIGINT,SIG_DFL) == SIG_ERR){ ERROR("register signale"); } while(1); return 0; }
捕捉管道破裂的訊息
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) void handle(int num) { if (num == SIGPIPE){ printf("捕捉到一條管道破裂的訊息n"); } } int main(int argc, char const *argv[]) { int num[2]; char buff[32] = "123"; if(pipe(num)){ ERROR("pipe error"); } if (signal(SIGPIPE,handle) == SIG_ERR){ ERROR("signal error"); } close(num[0]); write(num[1],buff,strlen(buff)); return 0; }
阻塞等待為子程序回收資源
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <string.h> void signal_handle(int signo) { printf("我是父程序,收到了子程序退出的訊號,為它回收資源n"); waitpid(-1,NULL,WNOHANG); //非阻塞方式回收資源 printf("為子程序回收資源成功n"); raise(SIGKILL); //給父程序傳送訊號,結束父程序 } int main(int argc,const char * argv[]) { pid_t pid; pid = fork(); if(pid == -1){ ERROR("fork error"); }else if(pid == 0){ sleep(5); printf("子程序執行結束了n"); exit(EXIT_SUCCESS); }else{ if(signal(SIGCHLD,signal_handle)==SIG_ERR) ERROR("signal error"); while(1); } return 0; }
用arlarm實現一個鬥地主機制
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) void handle(int num) { if (num == SIGALRM){ printf("自動出牌n"); } alarm(3); } int main(int argc, char const *argv[]) { char ch; if (signal(SIGALRM,handle) == SIG_ERR){ ERROR("signale error"); } alarm(3); while (1){ printf("請輸入您要出的牌>>"); ch = getchar(); getchar(); printf("%cn",ch); alarm(3); } return 0; }
(1)訊息佇列
(2)共用記憶體
(3)訊號燈集
4.2.1檢視
ipcs -q //檢視訊息佇列的命令
ipcs -m //檢視共用記憶體的命令
ipcs -s //檢視訊號燈集的命令
4.2.2刪除ipc的命令
ipcrm -q msqid //刪除訊息佇列命令
ipcrm -m shmid //刪除共用記憶體命令
ipcrm -s semid //刪除訊號燈集的命令
4.3.1訊息佇列的原理
訊息佇列也是藉助核心實現的,A程序將訊息放到訊息佇列中,佇列中的訊息
有訊息的型別和訊息的正文。B程序可以根據想取的訊息的型別從訊息佇列中
將訊息讀走。訊息佇列預設的大小是16384個位元組。如果訊息佇列中的訊息滿了,
A程序還想往佇列中發訊息,此時A程序阻塞。
4.3.2IPC程序間通訊鍵值的獲取
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #define ERROR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) int main(int argc, char const *argv[]) { key_t key; struct stat st; if ((key = ftok("/home/linux",'w')) == -1){ ERROR("ftok error"); } printf("key=%#xn",key); if (stat("/home/linux",&st)){ ERROR("stat error"); } printf("pro_id=%#x,devno=%#lx,ino=#=%#lxn",'w',st.st_dev,st.st_ino); return 0; }
結果圖:
4.3.3訊息佇列的範例:(不關注型別的)
標頭檔案:
#ifndef __MYHEAD_H__ #define __MYHEAD_H__ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <sys/msg.h> #include <string.h> #define PRINT_ERR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) #define MSGSIZE (sizeof(msg_t)-sizeof(long)) typedef struct mubuf{ long mtype; char text[512]; }msg_t; #endif
傳送方:
#include "myhead.h" int main(int argc, char const *argv[]) { key_t key; int msqid; msg_t msg ={ .mtype = 100, }; if((key = ftok("/home/linux/",'r'))==-1) PRINT_ERR("ftok get key error"); if((msqid = msgget(key,IPC_CREAT|0666))==-1) PRINT_ERR("create msg queue error"); while (1){ memset(msg.text,0,sizeof(msg.text)); fgets(msg.text,MSGSIZE,stdin); msg.text[strlen(msg.text) - 1] = ' '; msgsnd(msqid, &msg, MSGSIZE, 0); if (!strncmp(msg.text,"quit",4)){ break; } } msgctl(msqid, IPC_RMID, NULL); return 0; }
接受方:
#include "myhead.h" int main(int argc, char const *argv[]) { key_t key; int msgqid; msg_t msg; if ((key = ftok("/home/linux",'r')) == -1){ PRINT_ERR("ftok error"); } if ((msgqid = msgget(key, IPC_CREAT|0666)) == -1){ PRINT_ERR("msgget error"); } while (1){ memset(msg.text, 0, sizeof(msg.text)); msgrcv(msgqid, &msg, MSGSIZE,0,0); if (!strncmp("quit",msg.text,4)){ break; } printf("%sn",msg.text); } msgctl(msgqid,IPC_RMID,NULL); return 0; }
4.3.4訊息佇列的範例:(關注型別的)
標頭檔案:
#ifndef __MSGQUE_H__ #define __MSGQUE_H__ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <sys/msg.h> #include <string.h> typedef struct msgbuf { long id; char name[30]; char sex; int age; }msg_t; #define MSGSIZE (sizeof(msg_t)-sizeof(long)) #endif
傳送方:
#include "msgqueue.h" #include <head.h> int main(int argc, const char* argv[]) { key_t key; int msqid; if ((key = ftok("/home/linux/", 'r')) == -1) PRINT_ERR("ftok get key error"); if ((msqid = msgget(key, IPC_CREAT | 0666)) == -1) PRINT_ERR("create msg queue error"); msg_t m1 = { .id = 1, .name = "zhangsan", .sex = 'm', .age = 30, }; msgsnd(msqid, &m1, MSGSIZE, 0); msg_t m2 = { .id = 2, .name = "lisi", .sex = 'w', .age = 18, }; msgsnd(msqid, &m2, MSGSIZE, 0); msg_t m3 = { .id = 3, .name = "wangwu", .sex = 'm', .age = 22, }; msgsnd(msqid, &m3, MSGSIZE, 0); // msgctl(msqid, IPC_RMID, NULL); return 0; }
接受方:
#include "msgqueue.h" int main(int argc, const char* argv[]) { key_t key; int msqid; msg_t msg; if ((key = ftok("/home/linux/", 'r')) == -1) PRINT_ERR("ftok get key error"); if ((msqid = msgget(key, IPC_CREAT | 0666)) == -1) PRINT_ERR("create msg queue error"); memset(&msg, 0, sizeof msg); msgrcv(msqid, &msg, MSGSIZE, atoi(argv[1]), 0); printf("id=%ld,name=%s,sec=%c,age=%dn",msg.id,msg.name,msg.sex,msg.age); // msgctl(msqid, IPC_RMID, NULL); return 0; }
結果圖:
4.4.1原理:
共用記憶體:在核心空間建立共用記憶體,讓使用者的A和B程序都能夠存取到。通過這塊記憶體
進行資料的傳遞。共用記憶體所有的程序間通訊中效率最高的方式(不需要來回拷貝資料),共用記憶體的大小為 4k整數倍。
4.4.2範例
接受方:
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <string.h> #include <stdlib.h> #define PRINT_ERR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) int main(int argc, char const *argv[]) { key_t key; int shmid; char* over; if ((key = ftok("/home/linux", 'r')) == -1){ PRINT_ERR("ftok error"); } if ((shmid = shmget(key, 4096, IPC_CREAT|0666)) == -1){ PRINT_ERR("shemget error"); } if ((over = shmat(shmid, NULL, 0)) == (void*)-1){ PRINT_ERR("shmat error"); } while (1){ if (!strncmp("quit", over, 4))break; getchar(); printf("%sn",over); } if (shmdt(over)){ PRINT_ERR("shmdt error"); } shmctl(shmid,IPC_RMID,NULL); return 0; }
傳送方:
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <string.h> #include <stdlib.h> #define PRINT_ERR(msg) do{ printf("%s %s %dn", __FILE__, __func__, __LINE__); printf(msg); exit(-1); }while(0) int main(int argc, char const *argv[]) { key_t key; int shmid; char* over; if ((key = ftok("/home/linux", 'r')) == -1){ PRINT_ERR("ftok error"); } if ((shmid = shmget(key, 4096, IPC_CREAT|0666)) == -1){ PRINT_ERR("shmget errorn"); } if ((over = shmat(shmid, NULL, 0)) == (void*)-1){ PRINT_ERR("shmat errorn"); } while (1){ printf("請輸入>>"); fgets(over,4096,stdin); over[strlen(over) - 1] = ' '; if (!strncmp("quit",over,4)){ break; } } if (shmdt(over)){ PRINT_ERR("shmdt errorn"); } shmctl(shmid,IPC_RMID,NULL); return 0; }
號誌的原理
號誌:又叫訊號燈集,它是實現程序間同步的機制。在一個訊號燈集中可以有很多的訊號燈,這些訊號燈它們的工作相關不干擾。一般使用的時候使用的是二值訊號燈。
訊號燈集函數的封裝
sem.h
#ifndef __SEM_H__ #define __SEM_H__ int mysem_init(int nsems); int P(int semid, int semnum); int V(int semid, int semnum); int sem_del(int semid); #endif sem.c #include <head.h> union semun { int val; /* Value for SETVAL */ struct semid_ds* buf; /* Buffer for IPC_STAT, IPC_SET */ }; int semnum_init_value(int semid, int which, int value) { union semun sem = { .val = value, }; if (semctl(semid, which, SETVAL, sem) == -1) PRINT_ERR("semctl int value error"); return 0; } //初始化訊號燈集 int mysem_init(int nsems) { key_t key; int semid; // 1.通過ftok獲取鍵值 if ((key = ftok("/home/linux/", 'g')) == -1) PRINT_ERR("get key error"); // 2.如果不選擇就建立訊號燈集,如果存在返回已存在的錯誤 if ((semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666)) == -1) { if (errno == EEXIST) { //如果已存在,這裡呼叫semget,直接返回semid semid = semget(key, nsems, IPC_CREAT | 0666); } else { PRINT_ERR("create sem error"); } } else { // 3.初始化訊號燈集中的訊號燈 for (int i = 0; i < nsems; i++) { semnum_init_value(semid, i, !i); } } return semid; } //申請資源 int P(int semid, int semnum) { struct sembuf buf = { .sem_num = semnum, .sem_op = -1, .sem_flg = 0, }; if (semop(semid, &buf, 1)) PRINT_ERR("request resource error"); return 0; } //釋放資源 int V(int semid, int semnum) { struct sembuf buf = { .sem_num = semnum, .sem_op = 1, .sem_flg = 0, }; if (semop(semid, &buf, 1)) PRINT_ERR("free resource error"); return 0; } //刪除訊號燈集 int sem_del(int semid) { semctl(semid,0,IPC_RMID); }
用訊號燈集實現程序同步
寫端:
#include <head.h> #include "sem.h" int main(int argc, const char* argv[]) { key_t key; int shmid,semid; char* waddr; //0.號誌的初始化 semid = mysem_init(2); if(semid == -1){ printf("sem init error"); return -1; } // 1.獲取key if ((key = ftok("/home/linux", 'p')) == -1) PRINT_ERR("get key error"); // 2.建立共用記憶體 if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) == -1) PRINT_ERR("create share memory error"); // 3.將共用記憶體對映到使用者空間 if ((waddr = shmat(shmid, NULL, 0)) == (void*)-1) PRINT_ERR("shmat error"); printf("waddr = %pn", waddr); // 4.寫操作 while (1) { P(semid,0); printf("input > "); fgets(waddr, 4096, stdin); waddr[strlen(waddr) - 1] = ' '; if (strncmp(waddr, "quit", 4) == 0) break; V(semid,1); } // 5.取消地址對映 if (shmdt(waddr)) PRINT_ERR("shmdt error"); // 6.刪除共用記憶體 if (shmctl(shmid, IPC_RMID, NULL)) PRINT_ERR("shmrm error"); //7.刪除號誌 sem_del(semid); return 0; }
讀埠:
#include "sem.h" #include <head.h> int main(int argc, const char* argv[]) { key_t key; int shmid, semid; char* raddr; // 0.號誌的初始化 semid = mysem_init(2); if (semid == -1) { printf("sem init error"); return -1; } // 1.獲取key if ((key = ftok("/home/linux", 'p')) == -1) PRINT_ERR("get key error"); // 2.建立共用記憶體 if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) == -1) PRINT_ERR("create share memory error"); // 3.將共用記憶體對映到使用者空間 if ((raddr = shmat(shmid, NULL, 0)) == (void*)-1) PRINT_ERR("shmat error"); printf("waddr = %pn", raddr); // 4.讀操作 while (1) { P(semid,1); printf("raddr = %sn", raddr); if (strncmp(raddr, "quit", 4) == 0) break; V(semid,0); } // 5.取消地址對映 if (shmdt(raddr)) PRINT_ERR("shmdt error"); // 6.刪除共用記憶體 shmctl(shmid, IPC_RMID, NULL); //7.刪除號誌 sem_del(semid); return 0; }
以上就是C語言中程序間通訊的方式詳解的詳細內容,更多關於C語言程序通訊的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45