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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

进程间通信(一)

發布時間:2024/4/11 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进程间通信(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

進程間通信

文章目錄

  • 進程間通信
    • 一、進程間通信簡介
    • 二、進程間通訊的發展及分類:
    • 三、管道
    • 四、minishell

一、進程間通信簡介

  • 1.進程間是相互獨立的,每個進程都有自己的進程虛擬地址空間,二進程通訊需要介子,使得兩個進程都能訪問的公共資源;
  • 2.進程間通訊的目的:
  • 數據傳輸:一個進程需要將他的數據發送給另一個進程
  • 資源共享:多個進程間共享同樣的資源
  • 通知事件:一個進程需要向另一個或一組進程發送消息,通知它們發生了某種事件(如子進程退出時要通知父進程回收其資源等)
  • 進程控制:有些進程希望完全控制另一個進程的執行,此時控制進程希望能夠攔截另一個進程所有陷入和異常,并能及時的知道他的改變狀態

二、進程間通訊的發展及分類:

  • 1.管道
  • 匿名管道pipe
  • 命名管道
  • 2.System V進程間通訊
  • System V消息共享隊列
  • System V共享內存
  • System V信號量
  • 3.POSIX進程間通訊
  • 消息隊列
  • 共享內存
  • 信號量
  • 互斥量
  • 條件變量
  • 讀寫鎖

三、管道

  • 1.什么是管道:管道是內核中的一塊內存,構成一個隊列,使用一對文件描述符來進行訪問管理這個內存,讀文件描述符相當于從這個內存中取數據,寫文件描述符相當于往這塊內存中寫數據

  • 2.匿名管道

  • 匿名管道的創建

int pipe(int pipefd[2]);
  • 功能:是創建一個無名管道;

  • 參數:是兩個輸出型參數,fd表示文件描述符數組,其中fd[0]端表示讀端,fd[1]端表示寫端。

  • 返回值:創建成功返回0;失敗返回錯誤碼。


測試代碼:

例子:從鍵盤讀取數據,寫入管道,讀取管道,寫到屏幕 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main( void ) {int fds[2];char buf[100];int len;if ( pipe(fds) == -1 )perror("make pipe"),exit(1);// read from stdinwhile ( fgets(buf, 100, stdin) ) {len = strlen(buf);// write into pipeif ( write(fds[1], buf, len) != len ) {perror("write to pipe");break;}memset(buf, 0x00, sizeof(buf));// read from pipeif ( (len=read(fds[0], buf, 100)) == -1 ) {perror("read from pipe");break;}// write to stdoutif ( write(1, buf, len) != len ) {perror("write to stdout");break;}} }
  • 3.用fork來共享管道


站在文件描述符的角度:



站在內核角度:

共享管道實用的注意事項:

  • 管道使用完后一定要及時關閉文件描述符,防止資源泄漏
  • 創建子進程時,子進程會進程父進程的文件描述符表,此時子進程也就能訪問同一個管道
  • 如果父子進程同時讀取管道的內容,只有其中一個能夠成功讀取到管道中的數據,一旦有一個進程成功讀取到管道中的內容,那么該數據就不在管道中了,相當于把數據從管道中出隊了。
  • 管道內置了“同步互斥機制”,不會出現兩個進程一人讀取管道一般數據的情況。其中有如下幾種情況:
  • a.多個進程同時去讀寫管道,管道數據不會錯亂(內置同步互斥)b.如果管道為空,再去嘗試讀取管道數據,此時程序就會在read處阻塞。c.如果管道已滿,再去嘗試往管道中寫數據,此時程序就會在write處阻塞;

    四、minishell

    #include <stdio.h> #include <sys/wait.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h>char g_command[1024]; static char* pipe_command[] = {0};//該函數的功能是獲取命令行輸入的數據 int GetCommand() {//因為開始獲得的內存中的內容是不定的,所以使用前要先初始化memset(g_command,'\0',sizeof(g_command));//這里需要為'\0'留一個位置,不能把g_command全部用來讀取內容,否者就沒有結束標志,容易發生內存訪問越界if(fgets(g_command,sizeof(g_command)-1,stdin)==NULL){printf("fgets is error!\n");return -1;}//printf("g_command:%s\n",g_command);return 0; }//解析字符串 char** DealCommand(char* command) {if(command==NULL&&*command=='\0'){printf("dealcommand is error\n");return NULL;}//用來保存命令static char* argv[1024]={0};int argc=0;while(*command){//isspace函數用來去掉多余的空格//isspace的返回值:如果當前字符是空格返回1,否則返回0//注意'\0'在issapce函數中不算空格的,所以要進行判斷while(!isspace(*command)&&*command!='\0'){argv[argc]=command;argc++;//去找下一個空格while(!isspace(*command)&&*command!='\0'){command++;}*command='\0';}command++;}argv[argc]=NULL;//for(int i=0;i<argc;i++)//{// printf("%d:%s ",i,argv[i]);//}//printf("\n");return argv; }//進行重定向 int redirect(char * g_command) {char* ptr = g_command;char* file = NULL;int fd ;//用來標記是清空重定向還是追加重定向int redirect_type = -1;while(*ptr !='\0'){//如果當前字符是 > ,把他置為'\0',并判斷下一個位置是否為'\0'if(*ptr == '>'){*ptr++ = '\0';redirect_type++;if(*ptr == '>'){*ptr++ = '\0';redirect_type++;}//去掉多余的空格while(isspace(*ptr)){ptr++;}//file就是空格后面的第一個字符串file = ptr;//繼續找空格,在這兩個空格之間就是文件的名稱while(!isspace(*ptr)&&*ptr != '\0'){ptr++;}*ptr='\0';//如果redirect_type==0說明是清空重定向,如果==1說明是追加重新定向if(redirect_type == 0){fd = open(file,O_CREAT|O_TRUNC|O_WRONLY,0664);}else{fd = open(file,O_CREAT|O_APPEND|O_WRONLY,0664);}dup2(fd,1);}ptr++;}return 0; }//解析字符串,獲取管道的數量 int do_command(char * g_command) {int pipe_num = 0;char * ptr =g_command;pipe_command[pipe_num]=ptr;while(*ptr != '\0'){if(*ptr == '|'){pipe_num++;*ptr++ = '\0';pipe_command[pipe_num] = ptr;continue;}ptr++;}pipe_command[pipe_num + 1] = NULL;return pipe_num; }//進行程序替換 int exec() {redirect(g_command);char** argv=DealCommand(g_command);pid_t pid =fork();if(pid<0){printf("foek is error!\n");return -1;}else if(pid==0){//child//如果argc中為NULL,就直接返回if(argv[0]==NULL){exit(-1);}//進行替換,execvp第一個參數是可執行程序名,第二個參數是該可執行程序的參數組成的數組execvp(argv[0],argv);//execl("/usr/bin/ls","ls","-a",NULL);}else{//fatherwaitpid(pid,NULL,0);}return 0; }//添加管道功能 int do_pipe(int pipe_num) {int pid = 0;int i;int pipefd[10][2] = {{0}};char** argv = {NULL};for (i = 0;i <= pipe_num;i++){pipe(pipefd[i]);}for(i = 0;i <= pipe_num; i++){pid = fork();if(pid < 0){perror("fork is error!\n");continue;}else if(pid == 0){redirect(pipe_command[i]);argv = DealCommand(pipe_command[i]);if(i != 0){close(pipefd[i][1]);dup2(pipefd[i][0],0);}if(i != pipe_num){close(pipefd[i+1][0]);dup2(pipefd[i+1][1],1);}execvp(argv[0],argv);}else{close(pipefd[i][0]);close(pipefd[i][1]);waitpid(pid,NULL,0);}}return 0; }int main() {//循環讀數據while(1){printf("[dev@localhost dev]$ ");int ret = GetCommand();if(ret == -1){//如果讀取失敗,繼續循環讀取,不能直接break調continue;}//處理解析數據//char** argv = DealCommand(g_command);//進行替換//exec(argv);//exec();int num = do_command(g_command);do_pipe(num);}return 0; }

    總結

    以上是生活随笔為你收集整理的进程间通信(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

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