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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

LInux--进程间通信

發(fā)布時(shí)間:2024/4/13 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LInux--进程间通信 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

key標(biāo)識(shí)共享內(nèi)存的鍵值: 0/IPC_PRIVATE。 當(dāng)key的取值為IPC_PRIVATE,則函數(shù)shmget()將創(chuàng)建一塊新的共享內(nèi)存;如果key的取值為0,而參數(shù)shmflg中又設(shè)置IPC_PRIVATE這個(gè)標(biāo)志,則同樣會(huì)創(chuàng)建一塊新的共享內(nèi)存。返回值:如果成功,返回共享內(nèi)存標(biāo)識(shí)符;如果失敗,返回-1

2.1.3char * shmat ( int shmid, char *shmaddr, int flag)
參數(shù):
shmid:shmget函數(shù)返回的共享存儲(chǔ)標(biāo)識(shí)符
flag:決定以什么方式來(lái)確定映射的地址(通常為0)
返回值:
如果成功,則返回共享內(nèi)存映射到進(jìn)程中的地址;如果失敗,則返回- 1
2.1.4當(dāng)一個(gè)進(jìn)程不再需要共享內(nèi)存時(shí),需要把它從進(jìn)程地址空間中脫離。
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。

執(zhí)行 ./shm,執(zhí)行結(jié)果如下:

shm_segsz =1024 bytes

shm_cpid = 9503

shm_lpid = 9504

Hi, I am child process!

  • 多進(jìn)程讀寫范例
    多進(jìn)程讀寫即一個(gè)進(jìn)程寫共享內(nèi)存,一個(gè)或多個(gè)進(jìn)程讀共享內(nèi)存。下面的例子實(shí)現(xiàn)的是一個(gè)進(jìn)程寫共享內(nèi)存,一個(gè)進(jìn)程讀共享內(nèi)存。
  • (1)下面程序?qū)崿F(xiàn)了創(chuàng)建共享內(nèi)存,并寫入消息。

    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)下面程序?qū)崿F(xiàn)從共享內(nèi)存讀消息。

    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)編譯與執(zhí)行

    ① 編譯gcc shmwrite.c -o shmwrite。

    ② 執(zhí)行./shmwrite,執(zhí)行結(jié)果如下:

    key=50453281

    shm_id=688137

    ③ 編譯gcc shmread.c -o shmread。

    ④ 執(zhí)行./shmread,執(zhí)行結(jié)果如下:

    key=50453281

    shm_id=688137

    name:test1

    age 0

    name:test2

    age 1

    name:test3

    age 2

    ⑤ 再執(zhí)行./shmwrite,執(zhí)行結(jié)果如下:

    key=50453281

    shmget error: File exists
    可用 ipcrm -m 共享內(nèi)存標(biāo)識(shí)符大小即可。
    2.2管道通信
    2.2.1管道是單向的、先進(jìn)先出的,它把一個(gè)進(jìn)程的輸出和另一個(gè)進(jìn)程的輸入連接在一起。
    一個(gè)進(jìn)程(寫進(jìn)程)在管道的尾部寫入數(shù)據(jù),另一個(gè)進(jìn)程(讀進(jìn)程)從管道的頭部讀出數(shù)據(jù)
    2.2.2管道包括無(wú)名管道和有名管道兩種,前者用于父進(jìn)程和子進(jìn)程間的通信,后者可用于運(yùn)行于同一系統(tǒng)中的任意兩個(gè)進(jìn)程間的通信。
    無(wú)名管道創(chuàng)建:
    int pipe(int filedis[2]);
    當(dāng)一個(gè)管道建立時(shí),它會(huì)創(chuàng)建兩個(gè)文件描述符:
    filedis[0] 用于讀管道,
    filedis[1] 用于寫管道
    2.2.3管道用于不同進(jìn)程間通信。通常先創(chuàng)建一個(gè)管道,再通過(guò)fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程會(huì)繼承父進(jìn)程所創(chuàng)建的管道
    !!!注意:必須在系統(tǒng)調(diào)用fork( )前調(diào)用pipe( ),否則子進(jìn)程將不會(huì)繼承文件描述符
    2.3 消息隊(duì)列:
    消息隊(duì)列就是一個(gè)消息的鏈表.可以把消息看作一個(gè)記錄,具有特定的格式.進(jìn)程可以向中按照一定的規(guī)則添加新消息;另一些進(jìn)程則可以從消息隊(duì)列中讀走消息
    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:標(biāo)志位。
    返回值:與健值key相對(duì)應(yīng)的消息隊(duì)列描述字

    msgflag:
    IPC_CREAT
    創(chuàng)建新的消息隊(duì)列
    IPC_EXCL
    與IPC_CREAT一同使用,表示如果要?jiǎng)?chuàng)建的消息隊(duì)列已經(jīng)存在,則返回錯(cuò)誤。
    IPC_NOWAIT
    讀寫消息隊(duì)列要求無(wú)法得到滿足時(shí),不阻塞

    Msqid: 已打開(kāi)的消息隊(duì)列id
    Msgp: 存放消息的結(jié)構(gòu)
    Msgsz: 消息數(shù)據(jù)長(zhǎng)度
    Msgflg:
    發(fā)送標(biāo)志,有意義的msgflg標(biāo)志為IPC_NOWAIT,指明在消息隊(duì)列沒(méi)有足夠空間容納要發(fā)送的消息時(shí),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代表的消息隊(duì)列中讀取一個(gè)msgtyp類型的消息,并把消息存儲(chǔ)在msgp指向的msgbuf結(jié)構(gòu)中。在成功地讀取了一條消息以后,隊(duì)列中的這條消息將被刪除
    struct msgbuf
    {
    long mtype;/消息類型/
    char mtext[1]; /消息數(shù)據(jù)的首地址/
    }
    2.4 信號(hào)量
    2.4.1信號(hào)燈的含義介紹:
    信號(hào)量(又名:信號(hào)燈)與其他進(jìn)程間通信方式不大相同,主要用途是保護(hù)臨界資源.
    進(jìn)程可以根據(jù)它判定是否能夠訪問(wèn)某些共享資源。除了用于訪問(wèn)控制外,還可用于進(jìn)程同步
    2.4.2信號(hào)燈的分類:
    二值信號(hào)燈:信號(hào)燈的值只能取0或1,類似于互斥鎖。 但兩者有不同:
    信號(hào)燈強(qiáng)調(diào)共享資源,只要共享資源可用,其他進(jìn)程同樣可以修改信號(hào)燈的值;
    互斥鎖更強(qiáng)調(diào)進(jìn)程,占用資源的進(jìn)程使用完資源后,必須由進(jìn)程本身來(lái)解鎖。
    計(jì)數(shù)信號(hào)燈:信號(hào)燈的值可以取任意非負(fù)值
    2.4.3
    信號(hào)量的操作——semop函數(shù)
    信號(hào)量的值與相應(yīng)資源的使用情況有關(guān),當(dāng)它的值大于 0 時(shí),表示當(dāng)前可用的資源數(shù)的數(shù)量;當(dāng)它的值小于 0 時(shí),其絕對(duì)值表示等待使用該資源的進(jìn)程個(gè)數(shù)。信號(hào)量的值僅能由 PV 操作來(lái)改變。

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

    sem_op 參數(shù):
    sem_op > 0 信號(hào)加上 sem_op 的值,表示進(jìn)程釋放控制的資源;

    sem_op = 0 如果沒(méi)有設(shè)置 IPC_NOWAIT,則調(diào)用進(jìn)程進(jìn)入睡眠狀態(tài),直到信號(hào) 量的值為0;否則進(jìn)程不回睡眠,直接返回 EAGAINsem_op < 0 信號(hào)加上 sem_op 的值。若沒(méi)有設(shè)置 IPC_NOWAIT ,則調(diào)用進(jìn)程阻塞,直到資源可用;否則進(jìn)程直接返回EAGAIN

    sem_flg 參數(shù):
    該參數(shù)可設(shè)置為 IPC_NOWAIT 或 SEM_UNDO 兩種狀態(tài)。只有將 sem_flg 指定為 SEM_UNDO 標(biāo)志后,semadj (所指定信號(hào)量針對(duì)調(diào)用進(jìn)程的調(diào)整值)才會(huì)更新。 此外,如果此操作指定SEM_UNDO,系統(tǒng)更新過(guò)程中會(huì)撤消此信號(hào)燈的計(jì)數(shù)(semadj)。此操作可以隨時(shí)進(jìn)行—它永遠(yuǎn)不會(huì)強(qiáng)制等待的過(guò)程。調(diào)用進(jìn)程必須有改變信號(hào)量集的權(quán)限。

    sem_flg公認(rèn)的標(biāo)志是 IPC_NOWAIT 和 SEM_UNDO。如果操作指定SEM_UNDO,它將會(huì)自動(dòng)撤消該進(jìn)程終止時(shí)。在標(biāo)準(zhǔn)操作程序中的操作是在數(shù)組的順序執(zhí)行、原子的,那就是,該操作要么作為一個(gè)完整的單元,要么不。如果不是所有操作都可以立即執(zhí)行的系統(tǒng)調(diào)用的行為取決于在個(gè)人sem_flg領(lǐng)域的IPC_NOWAIT標(biāo)志的存在。對(duì)信號(hào)量最基本的操作就是進(jìn)行PV操作,而System V信號(hào)量正是通過(guò) semop 函數(shù)和 sembuf 結(jié)構(gòu)體的數(shù)據(jù)結(jié)構(gòu)來(lái)進(jìn)行PV操作的。當(dāng) sembuf 的第二個(gè)數(shù)據(jù)結(jié)構(gòu) sem_op 設(shè)置為負(fù)數(shù)時(shí),是對(duì)它進(jìn)行P操作,即減1操作;當(dāng)設(shè)置為正數(shù)時(shí),就是進(jìn)行V操作,即加1操作。

    重點(diǎn)介紹的是semop函數(shù)。該函數(shù)主要功能是對(duì)信號(hào)燈進(jìn)行P/V操作。

    P操作責(zé)把當(dāng)前進(jìn)程由運(yùn)行狀態(tài)轉(zhuǎn)換為阻塞狀態(tài),直到另外一個(gè)進(jìn)程喚醒它。操作為:申請(qǐng)一個(gè)空閑資源(把信號(hào)量減1),若成功,則退出;若失敗,則該進(jìn)程被阻塞;

    V操作負(fù)責(zé)把一個(gè)被阻塞的進(jìn)程喚醒,它有一個(gè)參數(shù)表,存放著等待被喚醒的進(jìn)程信息。操作為:釋放一個(gè)被占用的資源(把信號(hào)量加1),如果發(fā)現(xiàn)有被阻塞的進(jìn)程,則選擇一個(gè)喚醒之。

    semop函數(shù)原型如下:

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

    semop操作中:sembuf結(jié)構(gòu)的sem_flg成員可以為0、IPC_NOWAIT、SEM_UNDO 。為SEM_UNDO時(shí),它將使操作系統(tǒng)跟蹤當(dāng)前進(jìn)程對(duì)這個(gè)信號(hào)量的修改情況,如果這個(gè)進(jìn)程在沒(méi)有釋放該信號(hào)量的情況下終止,操作系統(tǒng)將自動(dòng)釋放該進(jìn)程持有的。

    sembuf結(jié)構(gòu)的sem_flg成員為SEM_UNDO時(shí),它將使操作系統(tǒng)跟蹤當(dāng)前進(jìn)程對(duì)這個(gè)信號(hào)量的修改情況,如果這個(gè)進(jìn)程在沒(méi)有釋放該信號(hào)量的情況下終止,操作系統(tǒng)將自動(dòng)釋放該進(jìn)程持有的信號(hào)量

    問(wèn)題描述:假設(shè)父子進(jìn)程對(duì)一個(gè)文件進(jìn)行寫操作,但是這個(gè)文件同一時(shí)間只能有一個(gè)進(jìn)程進(jìn)行寫操作。

    示例程序如下:

    #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;}

    在該程序中,父子進(jìn)程都有可能執(zhí)行P操作成功,因此,兩個(gè)進(jìn)程中的提示語(yǔ)句,交替顯示。若通過(guò)kill命令把其中一個(gè)進(jìn)程殺死,且該進(jìn)程還沒(méi)有執(zhí)行V操作釋放資源。若使用SEM_UNDO標(biāo)志,則操作系統(tǒng)將自動(dòng)釋放該進(jìn)程持有的信號(hào)量,從而使得另外一個(gè)進(jìn)程可以繼續(xù)工作。若沒(méi)有這個(gè)標(biāo)志,另外進(jìn)程將P操作永遠(yuǎn)阻塞。

    因此,一般建議使用SEM_UNDo標(biāo)志。

    總結(jié)

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

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。