先上一個多進程的簡單多進程實例,此實例將在同一個程序中建立兩個進程:編程
/* 程序說明: 建立兩個進程,進程一執行」ls -l「操做,進程二作sleep操做 主進程阻塞等待進程1結束,再等待進程2結束,程序結束 */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t child1,child2; child1 = fork(); //進程1 if(child1 == -1){ perror("child1 creat error:"); exit(1); }else if(child1 == 0){ if(execlp("ls","ls","-l",NULL) < 0){ perror("execlp error:"); exit(1); } exit(0); } child2 = fork(); //進程2 if(child2 == -1){ perror("child2 creat error:"); exit(1); }else if(child2 == 0){ sleep(3); exit(0); } // waitpid(child1,NULL,0); 主進程 wait(0); while(waitpid(child2,NULL,WNOHANG)==0){ printf("child2 not exit\n"); sleep(1); } exit(0); }
建立多進程的時候須要注意,不要連續建立多個進程,不然上面建立的子進程將同時建立下面的進程,向下面這樣:數組
child1 = fork(); child2 = fork();
經過下面代碼能夠看出子進程1同時也建立了進程2:安全
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t child1,child2,child_temp; child1 = fork(); child2 = fork(); if(child1 == -1){ perror("child1 creat error:"); exit(1); } if(child2 == -1){ perror("child2 creat error:"); exit(1); } if(child1 == 0){ sleep(2); // exit(0); wait(0); } if(child2 == 0){ sleep(3); exit(0); } // waitpid(child1,NULL,0); while(waitpid(child1,NULL,WNOHANG)==0){ printf("chil1 has not exit\n"); sleep(1); } while(waitpid(child2,NULL,WNOHANG)==0){ printf("child2 has not exit\n"); sleep(1); } exit(0); }
不少時候,不一樣的進程之間須要交換數據,即相互通訊。而進程之間的通行方式也有多種,爲了知足進程間通訊在不一樣場景下的需求:管道通訊(pipe),信號(signal),信號量(semaphore),共享內存(shared memory),消息隊列(message queue),套接字(socket)。socket
接下來就一一來探索。函數
管道分爲無名管道和有名管道。翻譯
無名管道:調試
一、基於文件描述符,只能用於具備親緣關係的進程之間的通訊;code
二、是一種單工的通訊協議,具備固定的讀斷和寫斷;索引
三、無名管道不屬於任何文件系統,而且只存在於內存中。隊列
編程細解:主要使用pipe()函數,例程爲一個父進程寫進,子進程讀取的一個進程間通訊實例。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <errno.h> #define MaxDataLen 256 #define DelayUTime 1 int main() { pid_t pid; int pipe_fd[2]; char buf[MaxDataLen]; const char data[] = "Pipe Test Program"; int real_read,real_write; memset(buf,0,sizeof(buf)); if(pipe(pipe_fd)<0) /* pipe運行機制: 函數原型:int pipe(int pipefd[2]); 描述:pipe()用於建立一個單向數據通道,能夠用於進程間通訊; 使用數組pipefd返回兩個文件描述符指管的兩端; pipefd[0]是指讀的管道。pipefd[1]是指寫的管道; 數據在已寫入管道而未被讀取時由內核提供緩衝。 */ { perror("creat pipe failed:"); /* perror運行機制: 函數原型:void perror(const char *S); 描述:當一個系統調用失敗時,它一般會返回-1並設置變量errno用於描述這個錯誤(這個值能夠在errno.h中找到)\ perror函數會翻譯這些值成爲可閱讀的信息。errno會在一個成功的系統調用會是庫函數調用後變成undefined。 程序中存在一個全局的錯誤表sys_errlist[],能夠被下標errno索引。 NOTES: sys_nerr & sys_errlist 在 <stdio.h> 中 SEE ALSO: err(),errno(),error(),strerror() */ exit(-1); } if((pid = fork()) == 0){ //子進程爲讀端 close(pipe_fd[1]); usleep(DelayUTime); if((real_read = read(pipe_fd[0],buf,MaxDataLen)) > 0){ printf("%d bytes:%s\n",real_read,buf); } close(pipe_fd[0]); exit(0); }else if(pid > 0){ //父進程爲寫端 close(pipe_fd[0]); if((real_write = write(pipe_fd[1],data,strlen(data))) != -1){ printf("wrote %d bytes:'%s'\n",real_write,data); } close(pipe_fd[1]); wait(0); exit(0); } }
有名管道:
一、它能夠用於互不相關的兩個進程間通訊;
二、在文件系統中可見,但仍是單工通訊;
三、遵循先進先出規則。
編程細解:能夠先使用 mkfifo 指令在磁盤中建立一個有名管道文件,而後再程序中打開;也能夠在程序中使用mkfifo()函數建立有名管道。讀寫依舊使用read(),write()函數。
mkfifo Linux指令: mkfifo [OPTION]... NAME... 描述:建立名爲NAME的fifo文件; options: -m, --mode=MODE 設置文件權限位模式 -Z 設置SELinux安全上下文的默認類型 例:mkfifo -m 777 /tmp/temp
對於有名管道,咱們使用一個寫端程序和一個讀端程序來看進程通訊:
/* fifo_write.c 寫端程序 */ #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> int main(int argc,char *argv[]) { int fifo_fd; char buf[] = "hello"; if((fifo_fd = open("/tmp/temp",O_WRONLY,0600)) < 0){ fifo_fd = mkfifo("/tmp/temp",0777); //如沒有此管道文件,mkfifo()建立管道文件 } if(write(fifo_fd,buf,strlen(buf)) > 0){ printf("Write '%s' to FIFO\n",buf); } close(fifo_fd); exit(1); }
/* fifo_read.c 讀端程序 */ #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc,char *argv[]) { int fifo_fd; char buf[256]; fifo_fd = open("/tmp/temp",O_RDONLY); if(fifo_fd < 0){ perror("open temp failed:"); exit(-1); } while(1){ memset(buf,0,sizeof(buf)); if(read(fifo_fd,buf,256) > 0){ printf("Read '%s' from FIFO\n",buf); } } close(fifo_fd); exit(1); }
這個程序調試須要用到兩個窗口,兩個程序分開編譯,先打開寫程序,再打開讀程序。