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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

LInux--进程间通信

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

1.進程間通信概念介紹:
1.1(1).數據傳輸
一個進程需要將它的數據發送給另一個進程
(2).資源共享
多個進程之間共享同樣的資源
(3)通知事件
一個進程需要向另一個或一組進程發送消息,通知它們發生了某種事件
(4).進程控制
有些進程希望完全控制另一個進程的執行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有操作,并能夠及時知道它的狀態改變
1.2Linux進程間通信(IPC)由以下幾部分發展而來:
1.UNIX進程間通信
2.基于System V進程間通信
3.POSIX進程間通信
2.進程間通信方式
2.1共享內存
進程間需要共享的數據被放在一個叫做IPC共享內存區域的地方,所有需要訪問該共享區域的進程都要把該共享區域映射到本進程的地址空間中去。系統V共享內存通過shmget獲得或創建一個IPC共享內存區域,并返回相應的標識符。內核在保證shmget獲得或創建一個共享內存區,初始化該共享內存區相應的shmid_kernel結構注同時,還將在特殊文件系統shm中,創建并打開一個同名文件,并在內存中建立起該文件的相應dentry及inode結構,新打開的文件不屬于任何一個進程(任何進程都可以訪問該共享內存區)。所有這一切都是系統調用shmget完成的。
2.1.1共享內存實現分為兩個步驟:
一、創建共享內存,使用shmget函數
二、映射共享內存,將這段創建的共享內存映射到具體的進程空間去,使用shmat函數
2.1.2 int shmget ( key_t key, int size, int shmflg )

key標識共享內存的鍵值: 0/IPC_PRIVATE。 當key的取值為IPC_PRIVATE,則函數shmget()將創建一塊新的共享內存;如果key的取值為0,而參數shmflg中又設置IPC_PRIVATE這個標志,則同樣會創建一塊新的共享內存。返回值:如果成功,返回共享內存標識符;如果失敗,返回-1

2.1.3char * shmat ( int shmid, char *shmaddr, int flag)
參數:
shmid:shmget函數返回的共享存儲標識符
flag:決定以什么方式來確定映射的地址(通常為0)
返回值:
如果成功,則返回共享內存映射到進程中的地址;如果失敗,則返回- 1
2.1.4當一個進程不再需要共享內存時,需要把它從進程地址空間中脫離。
int shmdt ( char *shmaddr )
2.1.5
#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <error.h>

#define SIZE 1024

int main()

{

int shmid ;char *shmaddr ;struct shmid_ds buf ;int flag = 0 ;int pid ;shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;if ( shmid < 0 ){perror("get shm ipc_id error") ;return -1 ;}pid = fork() ;if ( pid == 0 ){shmaddr = (char *)shmat( shmid, NULL, 0 ) ;if ( (int)shmaddr == -1 ){perror("shmat addr error") ;return -1 ;}strcpy( shmaddr, "Hi, I am child process!\n") ;shmdt( shmaddr ) ;return 0;} else if ( pid > 0) {sleep(3 ) ;flag = shmctl( shmid, IPC_STAT, &buf) ;if ( flag == -1 ){perror("shmctl shm error") ;return -1 ;}printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ;printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;shmaddr = (char *) shmat(shmid, NULL, 0 ) ;if ( (int)shmaddr == -1 ){perror("shmat addr error") ;return -1 ;}printf("%s", shmaddr) ;shmdt( shmaddr ) ;shmctl(shmid, IPC_RMID, NULL) ;}else{perror("fork error") ;shmctl(shmid, IPC_RMID, NULL) ;}return 0 ;

}

編譯 gcc shm.c –o shm。

執行 ./shm,執行結果如下:

shm_segsz =1024 bytes

shm_cpid = 9503

shm_lpid = 9504

Hi, I am child process!

  • 多進程讀寫范例
    多進程讀寫即一個進程寫共享內存,一個或多個進程讀共享內存。下面的例子實現的是一個進程寫共享內存,一個進程讀共享內存。
  • (1)下面程序實現了創建共享內存,并寫入消息。

    shmwrite.c源代碼如下:

    #include <stdio.h>

    #include <sys/ipc.h>

    #include <sys/shm.h>

    #include <sys/types.h>

    #include <unistd.h>

    #include <string.h>

    typedef struct{

    char name[8];int age;

    } people;

    int main(int argc, char** argv)

    {

    int shm_id,i;key_t key;char temp[8];people *p_map;char pathname[30] ;strcpy(pathname,"/tmp") ;key = ftok(pathname,0x03);if(key==-1){perror("ftok error");return -1;}printf("key=%d\n",key) ;shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600); if(shm_id==-1){perror("shmget error");return -1;}printf("shm_id=%d\n", shm_id) ;p_map=(people*)shmat(shm_id,NULL,0);memset(temp, 0x00, sizeof(temp)) ;strcpy(temp,"test") ;temp[4]='0';for(i = 0;i<3;i++){temp[4]+=1;strncpy((p_map+i)->name,temp,5);(p_map+i)->age=0+i;}shmdt(p_map) ;return 0 ;

    }

    (2)下面程序實現從共享內存讀消息。

    shmread.c源代碼如下:

    #include <stdio.h>

    #include <string.h>

    #include <sys/ipc.h>

    #include <sys/shm.h>

    #include <sys/types.h>

    #include <unistd.h>

    typedef struct{

    char name[8];int age;

    } people;

    int main(int argc, char** argv)

    {

    int shm_id,i;key_t key;people *p_map;char pathname[30] ;strcpy(pathname,"/tmp") ;key = ftok(pathname,0x03);if(key == -1){perror("ftok error");return -1;}printf("key=%d\n", key) ;shm_id = shmget(key,0, 0); if(shm_id == -1){perror("shmget error");return -1;}printf("shm_id=%d\n", shm_id) ;p_map = (people*)shmat(shm_id,NULL,0);for(i = 0;i<3;i++){printf( "name:%s\n",(*(p_map+i)).name );printf( "age %d\n",(*(p_map+i)).age );}if(shmdt(p_map) == -1){perror("detach error");return -1;}return 0 ;

    }

    (3)編譯與執行

    ① 編譯gcc shmwrite.c -o shmwrite。

    ② 執行./shmwrite,執行結果如下:

    key=50453281

    shm_id=688137

    ③ 編譯gcc shmread.c -o shmread。

    ④ 執行./shmread,執行結果如下:

    key=50453281

    shm_id=688137

    name:test1

    age 0

    name:test2

    age 1

    name:test3

    age 2

    ⑤ 再執行./shmwrite,執行結果如下:

    key=50453281

    shmget error: File exists
    可用 ipcrm -m 共享內存標識符大小即可。
    2.2管道通信
    2.2.1管道是單向的、先進先出的,它把一個進程的輸出和另一個進程的輸入連接在一起。
    一個進程(寫進程)在管道的尾部寫入數據,另一個進程(讀進程)從管道的頭部讀出數據
    2.2.2管道包括無名管道和有名管道兩種,前者用于父進程和子進程間的通信,后者可用于運行于同一系統中的任意兩個進程間的通信。
    無名管道創建:
    int pipe(int filedis[2]);
    當一個管道建立時,它會創建兩個文件描述符:
    filedis[0] 用于讀管道,
    filedis[1] 用于寫管道
    2.2.3管道用于不同進程間通信。通常先創建一個管道,再通過fork函數創建一個子進程,該子進程會繼承父進程所創建的管道
    !!!注意:必須在系統調用fork( )前調用pipe( ),否則子進程將不會繼承文件描述符
    2.3 消息隊列:
    消息隊列就是一個消息的鏈表.可以把消息看作一個記錄,具有特定的格式.進程可以向中按照一定的規則添加新消息;另一些進程則可以從消息隊列中讀走消息
    2.3.1msgget:
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgget(key_t key, int msgflg)

    key:鍵值,由ftok獲得。
    msgflg:標志位。
    返回值:與健值key相對應的消息隊列描述字

    msgflag:
    IPC_CREAT
    創建新的消息隊列
    IPC_EXCL
    與IPC_CREAT一同使用,表示如果要創建的消息隊列已經存在,則返回錯誤。
    IPC_NOWAIT
    讀寫消息隊列要求無法得到滿足時,不阻塞

    Msqid: 已打開的消息隊列id
    Msgp: 存放消息的結構
    Msgsz: 消息數據長度
    Msgflg:
    發送標志,有意義的msgflg標志為IPC_NOWAIT,指明在消息隊列沒有足夠空間容納要發送的消息時,msgsnd是否等待

    2.3.2 接收消息 msgrcv
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg)

    功能:
    從msqid代表的消息隊列中讀取一個msgtyp類型的消息,并把消息存儲在msgp指向的msgbuf結構中。在成功地讀取了一條消息以后,隊列中的這條消息將被刪除
    struct msgbuf
    {
    long mtype;/消息類型/
    char mtext[1]; /消息數據的首地址/
    }
    2.4 信號量
    2.4.1信號燈的含義介紹:
    信號量(又名:信號燈)與其他進程間通信方式不大相同,主要用途是保護臨界資源.
    進程可以根據它判定是否能夠訪問某些共享資源。除了用于訪問控制外,還可用于進程同步
    2.4.2信號燈的分類:
    二值信號燈:信號燈的值只能取0或1,類似于互斥鎖。 但兩者有不同:
    信號燈強調共享資源,只要共享資源可用,其他進程同樣可以修改信號燈的值;
    互斥鎖更強調進程,占用資源的進程使用完資源后,必須由進程本身來解鎖。
    計數信號燈:信號燈的值可以取任意非負值
    2.4.3
    信號量的操作——semop函數
    信號量的值與相應資源的使用情況有關,當它的值大于 0 時,表示當前可用的資源數的數量;當它的值小于 0 時,其絕對值表示等待使用該資源的進程個數。信號量的值僅能由 PV 操作來改變。

    在 Linux 下,PV 操作通過調用semop函數來實現。該函數定義在頭文件 sys/sem.h中,原型如下:int semop(int semid,struct sembuf *sops,size_t nsops);函數的參數 semid 為信號量集的標識符;參數 sops 指向進行操作的結構體數組的首地址;參數 nsops 指出將要進行操作的信號的個數。semop 函數調用成功返回 0,失敗返回 -1。semop 的第二個參數 sops 指向的結構體數組中,每個 sembuf 結構體對應一個特定信號的操作。因此對信號量進行操作必須熟悉該數據結構,該結構定義在 linux/sem.h,如下所示:struct sembuf{unsigned short sem_num; //信號在信號集中的索引,0代表第一個信號,1代表第二個信號 short sem_op; //操作類型short sem_flg; //操作標志}; 下面詳細介紹一下 sembuf 的幾個參數:

    sem_op 參數:
    sem_op > 0 信號加上 sem_op 的值,表示進程釋放控制的資源;

    sem_op = 0 如果沒有設置 IPC_NOWAIT,則調用進程進入睡眠狀態,直到信號 量的值為0;否則進程不回睡眠,直接返回 EAGAINsem_op < 0 信號加上 sem_op 的值。若沒有設置 IPC_NOWAIT ,則調用進程阻塞,直到資源可用;否則進程直接返回EAGAIN

    sem_flg 參數:
    該參數可設置為 IPC_NOWAIT 或 SEM_UNDO 兩種狀態。只有將 sem_flg 指定為 SEM_UNDO 標志后,semadj (所指定信號量針對調用進程的調整值)才會更新。 此外,如果此操作指定SEM_UNDO,系統更新過程中會撤消此信號燈的計數(semadj)。此操作可以隨時進行—它永遠不會強制等待的過程。調用進程必須有改變信號量集的權限。

    sem_flg公認的標志是 IPC_NOWAIT 和 SEM_UNDO。如果操作指定SEM_UNDO,它將會自動撤消該進程終止時。在標準操作程序中的操作是在數組的順序執行、原子的,那就是,該操作要么作為一個完整的單元,要么不。如果不是所有操作都可以立即執行的系統調用的行為取決于在個人sem_flg領域的IPC_NOWAIT標志的存在。對信號量最基本的操作就是進行PV操作,而System V信號量正是通過 semop 函數和 sembuf 結構體的數據結構來進行PV操作的。當 sembuf 的第二個數據結構 sem_op 設置為負數時,是對它進行P操作,即減1操作;當設置為正數時,就是進行V操作,即加1操作。

    重點介紹的是semop函數。該函數主要功能是對信號燈進行P/V操作。

    P操作責把當前進程由運行狀態轉換為阻塞狀態,直到另外一個進程喚醒它。操作為:申請一個空閑資源(把信號量減1),若成功,則退出;若失敗,則該進程被阻塞;

    V操作負責把一個被阻塞的進程喚醒,它有一個參數表,存放著等待被喚醒的進程信息。操作為:釋放一個被占用的資源(把信號量加1),如果發現有被阻塞的進程,則選擇一個喚醒之。

    semop函數原型如下:

    int semop(int semid, struct sembuf *sops, unsigned nsops);

    semop操作中:sembuf結構的sem_flg成員可以為0、IPC_NOWAIT、SEM_UNDO 。為SEM_UNDO時,它將使操作系統跟蹤當前進程對這個信號量的修改情況,如果這個進程在沒有釋放該信號量的情況下終止,操作系統將自動釋放該進程持有的。

    sembuf結構的sem_flg成員為SEM_UNDO時,它將使操作系統跟蹤當前進程對這個信號量的修改情況,如果這個進程在沒有釋放該信號量的情況下終止,操作系統將自動釋放該進程持有的信號量

    問題描述:假設父子進程對一個文件進行寫操作,但是這個文件同一時間只能有一個進程進行寫操作。

    示例程序如下:

    #include <stdio.h>
    //……此處省略了頭文件
    void P(int sid)
    {
    struct sembuf sem_p;
    sem_p.sem_num = 0;
    sem_p.sem_op = -1;
    sem_p.sem_flg = 0;

    if (semop(sid, &sem_p, 1) == -1){perror("p op failed");exit(1);}}void V(int sid){struct sembuf sem_p;sem_p.sem_num = 0;sem_p.sem_op = 1;//sem_p.sem_flg = SEM_UNDO;sem_p.sem_flg = 0;if (semop(sid, &sem_p, 1) == -1){perror("v op failed");exit(1);}}int main(int argc, char * argv[ ]){pid_t pid;int fd;key_t key;int sid;if ((fd = open("semset", O_RDWR | O_CREAT, 0666)) == -1){perror("open");exit( -1);}if ((key=ftok("semset", 'a')) == -1){perror("ftok");return -1;}if ((sid = semget(key, 1, IPC_CREAT | 0666)) == -1){perror("createSemset");exit(-1);}if( -1==semctl(sid, 0, SETVAL, 1) ){perror("SETVAL");exit(1);}if ((pid=fork()) == -1){perror("fork");exit(-1);}else if ( 0 == pid ){while(1){P(sid); printf("child writing\n");sleep(1);printf("child finish post\n");V(sid);}}else{while(1){P(sid);printf("parent writing");sleep(1);printf("parent writing finish post\n");V(sid);}}return 0;}

    在該程序中,父子進程都有可能執行P操作成功,因此,兩個進程中的提示語句,交替顯示。若通過kill命令把其中一個進程殺死,且該進程還沒有執行V操作釋放資源。若使用SEM_UNDO標志,則操作系統將自動釋放該進程持有的信號量,從而使得另外一個進程可以繼續工作。若沒有這個標志,另外進程將P操作永遠阻塞。

    因此,一般建議使用SEM_UNDo標志。

    總結

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

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