管道是針對對本地計算機的兩個進程之間的通訊而設計的通訊方式,管道創建後,實際得到兩個文件描述符,一個讀取另外一個寫入。最多見的IPC機制,經過PIPE系統調用。管道是單工的,數據只能向一個方向流動,須要雙向通訊時,須要創建起兩個管道。管道的本質是內核中的緩存。linux
#include <unistd.h> #include <stdio.h> #include <stdlib.h> /** *Desc:扇形多線程之間管道通訊 *author:xiao_dingo *since:2018-03-07 *email:wwc0524@163.com */ char *cmd1[3] = {"/bin/cat","/etc/passwd",NULL}; char *cmd2[3] = {"/bin/grep","root",NULL}; int main(void){ int fd[2]; if(pipe(fd) < 0){ perror("pipe error"); } int i = 0; pid_t pid; for(;i < 2; i++){ pid = fork(); if(pid < 0){ perror("fork error"); exit(1); }else if(pid == 0){//child process if(i == 0){ close(fd[0]); //將標準輸出重定向到管道的寫端 if(dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO){ perror("dup2 error"); } close(fd[1]); if(execvp(cmd1[0],cmd1) < 0){ perror("execvp error"); exit(1); } break; } if(i == 1){ close(fd[1]); //將標準輸入重定向到管道的讀端 if(dup2(fd[0],STDIN_FILENO) != STDIN_FILENO){ perror("dup2 error"); } close(fd[0]); if(execvp(cmd2[0],cmd2) < 0){ perror("execvp error"); exit(1); } break; } }else{//parent process if(i == 1){ close(fd[0]); close(fd[1]); wait(NULL); wait(NULL); } } } exit(0); }
#include <unistd.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> /** *Desc:不完整管道之間操做 *author:xiao_dingo *since:2018-03-08 *email:wwc0524@163.com */ void sig_handler(int signo){ if(signo == SIGPIPE){ printf("sigpipe occured\n"); } } void main(void){ int fd[2]; if(pipe(fd) < 0){ perror("pipe error"); exit(1); } pid_t pid; if((pid = fork()) < 0){ perror("fork error"); exit(1); }else if(pid > 0){//parent process sleep(5); close(fd[0]); if(signal(SIGPIPE,sig_handler) == SIG_ERR){ perror("signal sigpipe error"); exit(1); } char *s = "1234"; if(write(fd[1],s,sizeof(s)) != sizeof(s)){ fprintf(stderr,"%s,%s\n",strerror(errno),(errno == EPIPE) ? "EPIPE" : ",UNKNOW"); } }else{//child process close(fd[0]); close(fd[1]); } }
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char* pathname,mode_t mode);
System v IPC對象(消息隊列,共享內存和信號量)存在於內核中而不是文件系統中,由用戶控制釋放(用戶管理IPC對象的生命週期),不像管道和釋放由內核控制。IPC對象經過標識符來引用和訪問,全部的IPC對象在內核空間有惟一標識ID,在用戶空間的惟一標識稱爲Key緩存
#include <sys/msg.h> int msgget(key_t key,int flag);//查詢 int msgctl(int msgid,int cmd,struct msgid_ds *buf);//控制 int msgsnd(int magid,const void *ptr,szie_t nbytes,int flag);//發送 ssize_t msgrvc(int msgqid,void *ptr,size_t nbytes,long type,int flag);//接收
共享內存容許系統內兩個或多個進程共享同一塊內存空間,而且數據不用在客戶進程和服務器進程間複製,所以共享內存是通訊速度最快的一種IPC。
實現的機制簡單描述以下:一個進程在系統中申請開闢了一塊共享內存空間,而後使用這個共享內存空間的各個進程分別打開這個共享內存空間,並將這個內存空間映射到本身的進程空間上,這樣各個進程就能夠共同使用這個共享內存空間,就如同使用本身進程地址空間的內存同樣
要實現共享內存空間,內核作了許多工做:好比給每一個共享內存塊分發一個「身份證」、容許用戶進程將共享內存映射到各自的地址空間上、在進程提出申請之後將共享內存和進程地址空間脫離,並在適當的時候講共享內存刪除,讓其回到能夠被建立的狀態。
用戶利用共享內存實現進程間的通訊,實際上就是使用內核提供的服務完成對共享內存的創建、映射、脫離、刪除等。當創建並映射成功之後,進程間就能經過共享內存實現數據的交互。服務器
/** *shmget實現共享內存的創建或者打開 *當共享內存的鍵值key 還沒有存在時,調用這個函數而且指定shmflg 參數爲IPC_CREAT 能夠建立一個大小爲 size 的共享內存空間。假設key指定的共享內存已經存在,調用這個函數能夠打開這個共享內存,但不會建立。 * */ int shmget(key_t key, size_t size, int shmflg); /** *該函數將一個共享內存空間映射到調用進程的地址空間上,而且返回在進程地址空間中的地址。用戶拿到改地址後就能夠經過這個地址間接的訪問共享內存。 *shmid 參數就是shmget 函數的返回值,shmaddr 參數其實是指出了共享內存映射到進程地址空間上的位置,可是咱們通常不會指定這個地址,而是令其爲NULL ,讓內核選擇一個合適的地址。shmflg 參數是配合着shmaddr 參數使用的,在shmaddr 爲NULL時就變得沒有實際意義,所以一般指定爲0 */ void *shmat(int shmid,const void* shmaddr,int shmflg); /** *這個函數將一個進程已經映射了的共享內存脫離進程地址空間。shmaddr 參數就是在進程地址空間的地址,實際就是shmat 函數的返回值 */ int shmdt(const void* shmaddr); /** *此函數實際上有不少的功能,可是咱們通長用它將一個已經建立了的共享內存刪除,所謂刪除實際就是將它放回能夠被建立的共享內存隊列中。指定cmd 參數爲IPC_RMID,就能夠將shmid鍵值指定的共享內存刪除,而buf其實是能夠獲取這共享內存在內核中的狀態,若是不想了解能夠指定爲0 */ int shmctl(int shmid, int cmd, struct shmid_ds *buf);
用於進程間的huchi與同步,每種共享資源對應一個信號量,爲了便於大量共享資源的操做引入了信號量集,可對全部信息量一次性操做,對信號量集中全部操做能夠要求所有成功,也能夠部分紅功。
它是一個特殊變量,只容許對它進行等待和發送信號這兩種操做。多線程
#include <sys/sem.h> /** * * */ int semget(key_t key,int nsems,int semflg);