<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                > 包括進程通信中信號的概念及信號處理、管道通信編程、內存共享編程、隊列通信編程。 [TOC] ## 1 進程間通信 能夠實現進程間通信的方法有: - 信號(signal):進程之間相互通信或操作的一種機制 - 管道(pipe):同一臺機器的兩個進程間雙向通信 - 套接字(socket):允許在不同機器上的兩個進程間進行通信 - System V IPC機制: - 消息隊列(message queue):適用于信息傳遞頻繁而內容較少 - 信號量(semaphore):用于實現進程之間通信的同步問題 - 共享內存(shared memory):信息內容較多 ## 2 信號 信號是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式,可以在用戶空間和內核之間直接交互。信號事件的發生有兩個來源包括硬件來源(例如按下`Ctrl+C`)和軟件來源(例如`kill` `raise` `alarm` `setitimer` `sigation` `sigqueue`,以及一些非法運算) 通過 `kill -l` 列出系統支持的信號,如下所示: ``` 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX ``` 以上信號可分為三類: - [1,31] 都以"SIG"開頭,屬于非實時信號 - [34, 49] 都以"SIGREMIN" 開頭,從Unix系統中繼承下來的信號,稱為不可靠信號(非實時信號) - [50, 64]的都以"SIGRTMAX" 開頭,為了解決不可靠信號問題而進行更改和擴充的信號,稱為可靠信號(實時信號) 一個完整的信號聲明周期為: 1. 在內核進程產生信號 2. 在用戶進程進行信號注冊和信號注銷 3. 信號處理 一旦有信號產生,用戶進程對信號的響應有三種方式: - 執行默認操作(Linux對每種信號都規定了默認操作) - 捕捉信號(定義信號處理函數,當信號發生時,執行相應的處理函數) - 忽略信號(不作處理,但是SIGKILL和SEGSTOP無法忽略) > Linux 常見信號的含義及其默認操作 信號名 | 含義 | 默認操作 ---- | ---- | ---- SIGHUP | 在用戶終端連接結束時發出 | 終止 SIGINT | 中斷鍵 `Ctrl + C` | 終止 SIGQUIT | 退出鍵 `Ctrl + \` | 終止 SIGILL | 另一個進程企圖執行一條非法指令時發出 | 終止 SIGFPE | 發生致命的算術運算錯誤時發出 | 終止 SIGKILL | 立即結束程序的運行,不能被阻塞、處理或忽略 | 終止 SIGALRM | 定時器完成時發出,可用alarm函數來設置 | 終止 SIGSTOP | 掛起鍵 `Ctrl + Z`,用于暫停一個進程,不能被阻塞、處理或忽略 | 暫停進程 SIGCHLD | 子進程結束時向父進程發出 | 忽略 > 以下程序演示了父進程向子進程發送信號,結束子進程 ```c int main() { pid_t pid_res; int kill_res; pid_res = fork(); if (pid_res < 0) { // 創建子進程失敗 perror("創建子進程失敗"); exit(1); } else if (pid_res == 0) { // 子進程 raise(SIGSTOP); // 調用rasise 函數,發送SIGSTOP使子進程暫停 exit(0); } else { printf("子進程號為:%d\n", pid_res); if ((waitpid(pid_res, NULL, WNOHANG)) == 0) { if ((kill_res = kill(pid_res, SIGKILL)) == 0) { printf("kill %d返回:%d\n", pid_res, kill_res); } else { perror("kill 結束子進程失敗") } } } } /* int kill(pid_t, pid, int sig); - pid > 0 表示將信號傳給識別碼為 pid 的進程 - pid = 0 表示將信號傳給和當前進程在相同進程組的所有進程 - pid = -1 表示將信號廣播傳送給系統內所有的進程 - pid < 0 表示將信號傳給進程組識別碼為 pid 絕對值的所有進程 */ ``` 以下是signal函數的示例,展示了按下兩次`Ctrl + C` 后,終止進程的過程 ```c // Ctrl + C void fun_ctrl_c(); int main() { signal(SIGINT, fun_ctrl_c); // 令 SIGINT 信號調用函數 fun_ctrl_c while(1) { printf("無限循環,按<Ctrl + C>\n") sleep(3); } exit(0); } void fun_ctrl_c() { printf("按下Ctrl + C"); (void) signal(SIGINT, SIG_DFL); // 恢復 SIGINT 信號的默認操作 } /* #include <signal.h> void (*signal(int signum, void(* handler)(int))) (int); - SIG_IGN:忽略參數 signum 指定的信號 - SIG_DFL:重設參數 signum 指定的信號的默認操作 返回先前的處理函數指針,如有錯誤返回SIG_ERR,即-1 */ ``` ## 3 管道 管道的實質是一個內核緩沖區,進程以先進先出的方式從緩沖區中存取數據。 - pipe 為無名管道,用于相關進程之間的通信,如父進程和子進程,通過 `pipe()` 系統調用來創建,當最后一個使用它的進程關閉對它的引用時,pipe將自動撤銷 - FIFO 為命名管道,在磁盤上有對應的節點,但沒有數據塊(即只擁有名字和相應的訪問權限),通過mknod()系統調用和mkfifo()函數來建立,當不再被進程使用時,FIFO在內存中釋放,但磁盤節點仍然存在。 > 以下例子展示了無名管道(pipe)的創建和讀寫 ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <string.h> // 管道的創建和讀寫 int main() { pid_t pid_res; int r_num; int pipe_fd[2]; // pipe_fd[0]為管道讀取端,pipe_fd[1]為管道寫入端 char buf_r[100], buf_w[100]; memset(buf_r, 0, sizeof(buf_r)); // 將buf_r的前sizeof(buf_r)元素用0填充 if(pipe(pipe_fd) < 0) { printf("創建管道失敗"); return -1; } pid_res = fork(); if(pid_res < 0) { perror("創建子進程失敗"); exit(0); } else if(pid_res == 0) { // 子進程代碼塊 close(pipe_fd[1]); if((r_num = read(pipe_fd[0], buf_r, 100)) > 0) { printf("讀取到:%s\n", buf_r); close(pipe_fd[0]); exit(0); } } else { // 父進程代碼塊 close(pipe_fd[0]); printf("請從鍵盤輸入寫入管道的字符串:"); scanf("%s", buf_w); if((write(pipe_fd[1], buf_w, strlen(buf_w)))!= -1) { close(pipe_fd[1]); waitpid(pid_res, NULL, 0); // 阻塞父進程,等待子進程退出 exit(0); } } } ``` > 以下例子通過命名管道模擬了一個聊天功能,包括 `a.c` 與 b.c` 兩個文件,其中 `b.c` 與 `a.c`的區別是交換了 FILO_NAME_1 和 FILO_NAME_2 ```c // a.c #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <sys/select.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #define FILO_NAME_1 ".__fifo__1" #define FILO_NAME_2 ".__fifo__2" int main() { mkfifo(FILO_NAME_1, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH); mkfifo(FILO_NAME_2, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH); printf("創建管道成功\n"); int wfd = open(FILO_NAME_1, O_RDWR); int rfd = open(FILO_NAME_2, O_RDWR); if (wfd <=0 || rfd <= 0) { return 0; } printf("a的終端\n"); fd_set read_fd; struct timeval net_timer; char str[32]; int i; int len; while (1) { FD_ZERO(&read_fd); FD_SET(rfd, &read_fd); FD_SET(fileno(stdin), &read_fd); net_timer.tv_sec = 5; net_timer.tv_usec = 0; memset(str, 0, sizeof(str)); if (i = select(rfd+1, &read_fd, NULL, NULL, &net_timer) <= 0) { continue; } if (FD_ISSET(rfd, &read_fd)) { read(rfd, str, sizeof(str)); // 讀取管道,將管道內容存入str printf("a讀取到:%s\n", str); } fgets(str, sizeof(str), stdin); len = write(wfd, str, strlen(str)); // 寫入管道 } close(rfd); close(wfd); } ``` > 高級管道可以參見 `popen` 函數 ## 4 消息隊列 消息隊列是一系列保存在內核中的消息的列表,用戶進程可以向消息隊列存取消息。 消息隊列產生后,除非明確的刪除,產生的隊列會一致保留在系統中,隊列的個數是有限的(注意不要泄露),使用已達到上限,msgget調動會失敗,提示"no space left on device" 其常用函數為: 函數名稱 | 函數功能 | 函數原型 | 函數返回值 ---- | ---- | ---- | ---- fotk | 由文件路徑和工程ID生成標準key(通過 ftok 建立一個 用于 IPC 通信的 ID 值) | `key_t ftok(char *pathName, char projectId);` | 成功返回 key_t 的值,失敗返回 -1,失敗原因存于 errno 中 msgget | 創建或打開消息隊列 | `int msgget(key_t key, int msgFlag` | 執行成功返回消息隊列識別號,失敗返回-1,失敗原因存于 errno 中 msgsnd | 將消息送入消息隊列 | `int msgsnd(int msgId, struct msgbuf *msgp, int msgSize, int msgFlag)` | 執行成功返回0,失敗返回-1,失敗原因存于 errno 中 msgrcv | 從消息隊列讀取消息 | `int msgrcv(int msgId, struct msgbuf *msgp, int msgSize, long msgType, int msgFlag)` | 執行成功返回實際讀取的消息數據長度,否則返回-1,錯誤原因存于 errno 中 msgctl | 控制消息隊列 | `msgctl (int msqId, int cmd, struct msqid_ds *buf)` | > 利用消息隊列進行通信的示例 ```c /* 利用消息隊列進行通信 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/msg.h> #include <sys/ipc.h> #include <unistd.h> struct msgbuf { long msg_type; char msg_text[512]; }; int main() { int qid; key_t key; if (key = ftok(".", 'a') == -1) { // 產生標準的 key perror("產生標準的key出錯"); exit(1); } if ((qid=msgget(key, IPC_CREAT|0666))==-1) { perror("創建消息隊列出錯"); exit(1); } printf("打開消息隊列:%d\n", qid); struct msgbuf msg; puts("輸入要加入到消息隊列的消息:"); if (fgets((&msg)->msg_text, 512, stdin) == NULL) { puts("沒有消息"); exit(1); } msg.msg_type = getpid(); int len = strlen(msg.msg_text); if (msgsnd(qid, &msg, len, 0) < 0) { perror("添加消息出錯"); exit(1); } if (msgrcv(qid, &msg, 512, 0, 0) < 0) { perror("讀取消息出錯"); exit(1); } printf("讀取的消息是:%s\n", (&msg)->msg_text); if (msgctl(qid, IPC_RMID, NULL) < 0) { perror("刪除消息隊列出錯"); exit(1); } exit(0); } ``` ## 5 共享內存 共享內存允許兩個或多個進程共享一個給定的存儲區,這一段存儲區可以被兩個或兩個以上的進程映射至自身的地址空間中。 - 共享內存的好處是通信效率非常高。 - 可以通過內存映射機制實現,也可以通過Unix System V共享內存機制實現。 - 常用函數如下: - mmap:建立共享內存映射 - munmap:接觸共享內存映射 - shmget:獲取共享內存區域的ID - shmat:建立映射共享內存 - shmdt:接觸共享內存映射 ------ 內存映射(memory map)機制使進程之間通過映射同一個普通文件實現共享內存,通過 mmap() 系統調用實現,普通文件被映射到進程地址空間后,進程可以像訪問普通內存一樣對文件進行訪問,不必再調用 read 和 write 等文件操作函數 > 以下示例中,先調用 mmap 映射內存,然后調用 fork 函數創建進程;在調用 fork 函數之后,子進程繼承父進程匿名映射的地址空間,同樣也繼承 mmap 函數的返回地址, ```c // 匿名內存映射 #include <sys/types.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { char name[4]; int age; } people; int main(int argc, char** argv) { int i; people *p_map; char tmp; p_map = (people *) mmap(NULL, sizeof(people) * 10, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); pid_t pid_res = fork(); if (pid_res < 0) { perror("創建子進程失敗"); exit(0); } else if (pid_res == 0) { // 子進程代碼塊 sleep(2); for (i = 0; i < 5; i++) { printf("子進程讀取 - 第 %d 個人的年齡是:%d\n", i+i, (*(p_map+i)).age); } (*p_map).age = 110; munmap(p_map, sizeof(people) * 10); // 解除內存映射關系 exit(0); } else { tmp = 'a'; for (i = 0; i < 5; i++) { tmp += 1; memcpy((*(p_map + i)).name, &tmp, 2); (*(p_map+i)).age = 20 + i; } sleep(5); printf("父進程讀取 - 五個人的年齡和是:%d\n", (*p_map).age); munmap(p_map, sizeof(people) * 10); } } /* > gcc test.c -o test > /data/Code/C/$ ./test 子進程讀取 - 第 0 個人的年齡是:20 子進程讀取 - 第 2 個人的年齡是:21 子進程讀取 - 第 4 個人的年齡是:22 子進程讀取 - 第 6 個人的年齡是:23 子進程讀取 - 第 8 個人的年齡是:24 父進程讀取 - 五個人的年齡和是:110 */ ``` > 與 mmap 系統調用通過映射一個普通文件實現共享內存不同,UNIX System V 共享內存是通過映射特殊文件系統 shm 中的文件實現進程間的共享內存通信
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看