UNIX進(jìn)程間通信(IPC) —— 管道聋呢、消息隊(duì)列、信號(hào)量颠区、共享內(nèi)存

Unix進(jìn)程間通信(IPC)

IPC概念:

進(jìn)程間通信IPC削锰,Inter-Process Communication),指至少兩個(gè)進(jìn)程線程間傳送數(shù)據(jù)或信號(hào)的一些技術(shù)或方法毕莱。進(jìn)程是計(jì)算機(jī)系統(tǒng)分配資源的最小單位(嚴(yán)格說(shuō)來(lái)是線程)器贩。每個(gè)進(jìn)程都有自己的一部分獨(dú)立的系統(tǒng)資源,彼此是隔離的朋截。為了能使不同的進(jìn)程互相訪問(wèn)資源并進(jìn)行協(xié)調(diào)工作蛹稍,才有了進(jìn)程間通信。舉一個(gè)典型的例子部服,使用進(jìn)程間通信的兩個(gè)應(yīng)用可以被分類為客戶端和服務(wù)器(見(jiàn)主從式架構(gòu))唆姐,客戶端進(jìn)程請(qǐng)求數(shù)據(jù),服務(wù)端回復(fù)客戶端的數(shù)據(jù)請(qǐng)求廓八。有一些應(yīng)用本身既是服務(wù)器又是客戶端奉芦,這在分布式計(jì)算中胆描,時(shí)常可以見(jiàn)到仗阅。這些進(jìn)程可以運(yùn)行在同一計(jì)算機(jī)上或網(wǎng)絡(luò)連接的不同計(jì)算機(jī)上昌讲。

進(jìn)程間通信技術(shù)包括消息傳遞、同步减噪、共享內(nèi)存和遠(yuǎn)程過(guò)程調(diào)用短绸。IPC是一種標(biāo)準(zhǔn)的Unix通信機(jī)制。

使用IPC 的理由:

  • 信息共享:Web服務(wù)器筹裕,通過(guò)網(wǎng)頁(yè)瀏覽器使用進(jìn)程間通信來(lái)共享web文件(網(wǎng)頁(yè)等)和多媒體醋闭;
  • 加速:維基百科使用通過(guò)進(jìn)程間通信進(jìn)行交流的多服務(wù)器來(lái)滿足用戶的請(qǐng)求;
  • 模塊化;
  • 私有權(quán)分離.

與直接共享內(nèi)存地址空間的多線程編程相比朝卒,IPC的缺點(diǎn):[1]

  • 采用了某種形式的內(nèi)核開(kāi)銷证逻,降低了性能;
  • 幾乎大部分IPC都不是程序設(shè)計(jì)的自然擴(kuò)展,往往會(huì)大大地增加程序的復(fù)雜度抗斤。

一囚企、管道

1、特點(diǎn):

  1. 管道是一種半雙工的通信方式(即數(shù)據(jù)只能單向流動(dòng))瑞眼,也有部分系統(tǒng)上實(shí)現(xiàn)了全雙工的管道龙宏,出于程序可移植性考慮,建議使用半雙工管道伤疙,全雙工的通信可由其它方式實(shí)現(xiàn)银酗,例如:消息隊(duì)列,Unix域套接字徒像。

  2. 管道分為兩種黍特,無(wú)名管道和有名管道。

    • 無(wú)名管道:

    最早出現(xiàn)的管道是沒(méi)有名字的锯蛀,因此只能用于父子進(jìn)程間通信灭衷,父進(jìn)程通過(guò)fork()系統(tǒng)調(diào)用創(chuàng)建一個(gè)子進(jìn)程,然后通過(guò)管道通信谬墙。

    • 有名管道(FIFO):

    有名管道也叫FIFO今布,由于磁盤中存在實(shí)際的管道文件,前者沒(méi)有拭抬,所以叫有名管道部默。FIFO的意思是(first in ,first out),先進(jìn)先出造虎。FIFO是一個(gè)(單向的)半雙工數(shù)據(jù)流傅蹂,不同于普通管道的是,每個(gè)FIFO都有一個(gè)對(duì)應(yīng)文件的路徑名與之關(guān)聯(lián),因此它能完成多個(gè)無(wú)親緣關(guān)系進(jìn)程之間的通信份蝴。

  3. FIFO和無(wú)名管道的數(shù)據(jù)都存在內(nèi)核的內(nèi)存緩沖區(qū)中犁功,大小一般為一頁(yè)(4K)。不同的是婚夫,F(xiàn)IFO將內(nèi)核緩沖區(qū)的數(shù)據(jù)映射到了實(shí)際的文件節(jié)點(diǎn)浸卦,可以在磁盤中看到對(duì)應(yīng)的文件,所以叫有名管道案糙,而無(wú)名管道在磁盤中沒(méi)有對(duì)應(yīng)文件限嫌,因此稱無(wú)名管道

  4. 無(wú)名管道通過(guò)<unistd.h>頭文件中的pipe()創(chuàng)建时捌,有名管道(FIFO)通過(guò)<sys/stat.h>中的mkfifo()創(chuàng)建怒医。

  5. 管道通過(guò)read()write()進(jìn)行讀寫(xiě)操作,管道內(nèi)核緩沖區(qū)中的數(shù)據(jù)一旦被取走奢讨,管道中將不存在稚叹。當(dāng)內(nèi)核緩沖區(qū)滿的時(shí)候,write()寫(xiě)操作將被阻塞拿诸,直到緩沖區(qū)有空閑再繼續(xù)扒袖。同理,當(dāng)緩沖區(qū)數(shù)據(jù)為空時(shí)佳镜,read()操作將阻塞僚稿,直到有新數(shù)據(jù)時(shí)再返回。

  6. 當(dāng)進(jìn)程終止時(shí)蟀伸,管道就完全被刪除了。

  • 無(wú)名管道

1缅刽、過(guò)程

  1. 創(chuàng)建管道

    #include <unistd.h>
    pipe(int fd[2]) 
    
  2. 通過(guò)fork()創(chuàng)建子進(jìn)程

    // 返回值 >=0:成功 <0:錯(cuò)誤
    // 如果是父進(jìn)程則返回子進(jìn)程 id,子進(jìn)程則返回 0
    fork()
    
  3. read()write()讀寫(xiě)緩沖區(qū)的數(shù)據(jù)

2啊掏、例子

  • pipe.c
#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd[2];  // 管道描述符
    pid_t pid;  // 進(jìn)程id
    char buff[20];  // 緩沖區(qū)長(zhǎng)度
    if(pipe(fd) < 0){
        printf("創(chuàng)建管道失敗\n");
    }
    pid = fork();   // 創(chuàng)建子進(jìn)程
    if(pid < 0){
        printf("fork()失敗\n");
    }else if (pid > 0){ // 大于0為主進(jìn)程
        close(fd[0]);   // 關(guān)閉主進(jìn)程讀端
        write(fd[1],"hello world\n",12);
    }else{  // 小于0為子進(jìn)程
        close(fd[1]);   // 關(guān)閉子進(jìn)程寫(xiě)端
        sleep(2);
        read(fd[0], buff, 20);
        printf("讀到的數(shù)據(jù):%s\n", buff);
    }
    return 0;
}
  • 有名管道FIFO

1、過(guò)程

  1. 按以下示例衰猛,先運(yùn)行read_fifo.c迟蜜,創(chuàng)建管道文件(注意: 此時(shí)管道文件必須不存在,否則會(huì)出錯(cuò))啡省。
  2. 因?yàn)榇藭r(shí)管道中還沒(méi)有數(shù)據(jù)娜睛,read()處于阻塞狀態(tài),等待數(shù)據(jù)卦睹。
  3. 再運(yùn)行write_fifo.c畦戒,向管道中寫(xiě)入數(shù)據(jù),此時(shí)read()打印write_fifo.c寫(xiě)入的數(shù)據(jù)结序。

2障斋、例子

  • read_fifo.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>

int main()
{
    int fd,len;
    char buff[1024];    //管道緩沖區(qū)大小
  if(mkfifo("/Users/meetmax/CWork/fifo1", 0666) < 0)
  {     // 創(chuàng)建FIFO管道,此時(shí)`fif01`文件必須不存在,否則報(bào)錯(cuò)
        perror("Create FIFO Failed");
        exit(1);
  } 
  
    if((fd = open("/Users/meetmax/CWork/fifo1", O_RDONLY)) < 0) 
    {   // 以只讀模式打開(kāi)FIFO,和打開(kāi)普通文件一樣
        perror("Open FIFO Failed");
        exit(1);
    }
     // 如果管道中有數(shù)據(jù)垃环,讀取FIFO管道
    while((len = read(fd, buff, 1024)) > 0)
        printf("Read message: %s", buff);

    close(fd);  // 關(guān)閉FIFO文件
    return 0;
}
  • write_fifo.c
#include<stdio.h>
#include<stdlib.h>   // exit
#include<fcntl.h>    // O_WRONLY
#include<sys/stat.h>
#include<time.h>     // time
#include <time.h>

int main()
{
    int fd;
    int n, i;
    char buf[1024];
    time_t tp;

    printf("I am %d process.\n", getpid()); // 說(shuō)明進(jìn)程ID
    
    if((fd = open("/Users/meetmax/CWork/fifo1", O_WRONLY)) < 0) 
      // 以寫(xiě)打開(kāi)一個(gè)FIFO 
    {
        perror("Open FIFO Failed");
        exit(1);
    }

    for(i=0; i<10; ++i)
    {
        time(&tp);  // 取系統(tǒng)當(dāng)前時(shí)間
        n=sprintf(buf,"Process %d's time is %s",getpid(),ctime(&tp));
        printf("Send message: %s", buf); // 打印
        if(write(fd, buf, n+1) < 0)  // 寫(xiě)入到FIFO中
        {
            perror("Write FIFO Failed");
            close(fd);
            exit(1);
        }
        sleep(1);  // 休眠1秒
    }

    close(fd);  // 關(guān)閉FIFO文件
    return 0;
}

XIS IPC(基于System V 的IPC函數(shù))

除管道外邀层,還有3種IPC的進(jìn)程間的通信,分別為:消息隊(duì)列遂庄、信號(hào)量和共享內(nèi)存寥院。這3個(gè)IPC有兩種實(shí)現(xiàn)方式,分別為基于System VPOSIX的進(jìn)程間通信涛目。

  • 維基百科

System V

UNIX系統(tǒng)五[來(lái)源請(qǐng)求](英語(yǔ):UNIX System V)秸谢,是Unix操作系統(tǒng)眾多版本中的一支。它最初由AT&T開(kāi)發(fā)泌绣,在1983年第一次發(fā)布钮追,因此也被稱為AT&T System V

POSIX

可移植操作系統(tǒng)接口(英語(yǔ):Portable Operating System Interface阿迈,縮寫(xiě)為POSIX)元媚,是IEEE為要在各種UNIX操作系統(tǒng)上運(yùn)行軟件,而定義API的一系列互相關(guān)聯(lián)的標(biāo)準(zhǔn)的總稱苗沧,其正式稱呼為IEEE Std 1003刊棕,而國(guó)際標(biāo)準(zhǔn)名稱為ISO/IEC 9945。

System V 出現(xiàn)比 POSIX 要早待逞,可以說(shuō)POSIX是對(duì)System V的改進(jìn)甥角,POSIX API使用比前者更加簡(jiǎn)單高效,但是為什么兩者仍然同時(shí)存在呢识樱?還是一個(gè)移植性的問(wèn)題嗤无,雖然現(xiàn)在新的程序都基于POSIX標(biāo)準(zhǔn),但是仍然有很多舊的程序使用了基于System V的IPC怜庸,因此兩者都保留了当犯。本文的IPC基于System V的IPC函數(shù)。

二割疾、消息隊(duì)列

1嚎卫、特點(diǎn)

  1. 消息隊(duì)列是消息的鏈表,存儲(chǔ)在內(nèi)核中宏榕,由消息隊(duì)列標(biāo)識(shí)符標(biāo)識(shí)拓诸。
  2. 消息隊(duì)列是隨內(nèi)核持續(xù)的,進(jìn)程終止時(shí)麻昼,消息隊(duì)列及其內(nèi)容不會(huì)被刪除奠支,除非內(nèi)核重啟或者調(diào)用msgctl()顯式的刪除消息隊(duì)列。
  3. 消息隊(duì)列沒(méi)有維護(hù)引用計(jì)數(shù)器(打開(kāi)文件有這種計(jì)數(shù)器)涌献,所以隊(duì)列被刪除后胚宦,仍在使用該隊(duì)列的進(jìn)程會(huì)出錯(cuò)返回。

2、過(guò)程

  1. 先定義消息隊(duì)列結(jié)構(gòu)struct msg_form枢劝,每條消息都包含:
    • 消息隊(duì)列類型:long類型的mtype
    • 消息數(shù)據(jù):char *類型的字符串
  2. 通過(guò)文件的路徑名和項(xiàng)目ID(0~255之間)井联,調(diào)用ftok()獲取IPC,獲取key值您旁。創(chuàng)建XSI IPC結(jié)構(gòu)都應(yīng)指定一個(gè)鍵烙常,這個(gè)鍵的數(shù)據(jù)類型是系統(tǒng)數(shù)據(jù)類型key_t,通常在頭文件<sys/types.h>中定義鹤盒。
  3. 接著調(diào)用msgget()函數(shù)蚕脏,使用key作為其中一個(gè)參數(shù),由內(nèi)核將key變成IPC的標(biāo)識(shí)符侦锯,在這里就是消息隊(duì)列ID驼鞭。
  4. 拿到IPC標(biāo)識(shí)符后,通過(guò)msgsnd()msgrcv()分別發(fā)送和接收消息尺碰。

3挣棕、示例

  • msg_client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <unistd.h>


#define MSG_FILE "/Users/meetmax/CWork/msg_file"

// 消息結(jié)構(gòu)
struct msg_form {
    long mtype;    
    char mtext[256];
};

int main(){
    int msqid;  // 消息隊(duì)列id
    key_t key;  // 鍵值
    struct msg_form msg;

    //獲取key值
    if((key = ftok(MSG_FILE,100)) < 0){
        perror("獲取key值失敗\n");
        exit(0);
    }

    printf("key 值為: %d",key);

    if((msqid = msgget(key,IPC_CREAT|0777)) < 0){
        perror("獲取消息隊(duì)列失敗");
        exit(0);
    }
    printf("消息隊(duì)列id: %d \n",msqid);
    printf("進(jìn)程id: %d \n",getpid());

    msg.mtype = 888;    // 設(shè)置消息類型
    sprintf(msg.mtext,"hello,I'm client %d\n",getpid());
    msgsnd(msqid,&msg,sizeof(msg.mtext),0);

    // 獲取777類型的消息
    msgrcv(msqid, &msg, 256, 999, 0);
    printf("Client: receive msg.mtext is: %s.\n", msg.mtext);
    printf("Client: receive msg.mtype is: %ld.\n", msg.mtype);
    return 0;
}
  • msg_server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <unistd.h>

#define MSG_FILE "/Users/meetmax/CWork/msg_file"
struct msg_form{
    long mtype;
    char mtext[256];
};
int main()
{
    int msqid;
    key_t key;
    struct msg_form msg;
    //獲取key值
    if((key = ftok(MSG_FILE,100)) < 0){
        perror("獲取key失敗");
        exit(1);
    }
    //打印key值
    printf("key的值為 %d \n",key);
    //根據(jù)key值創(chuàng)建消息隊(duì)列
    if((msqid = msgget(key,IPC_CREAT|0777)) < 0){
        perror("創(chuàng)建消息隊(duì)列失敗");
        exit(1);
    }
    printf("消息隊(duì)列id為 : %d \n",msqid);
    printf("進(jìn)程id為 : %d \n",getpid());
    while(1)
    {
        //接受888類型的消息        
        msgrcv(msqid,&msg,256,888,0);
        printf("Server:receive msg.mtext: %s \n",msg.mtext);
        printf("Server:receive msg.xxx: %ld \n",msg.mtype);
        msg.mtype = 999;
        sprintf(msg.mtext,"hello I'm server: %d \n",getpid());
        //發(fā)送消息
        msgsnd(msqid,&msg,sizeof(msg.mtext),0);
    }
    return 0;
}

三、信號(hào)量

1亲桥、特點(diǎn)

  1. 信號(hào)量類似鎖機(jī)制洛心,能夠使臨界區(qū)內(nèi)的資源在某一時(shí)刻只能被一個(gè)進(jìn)程訪問(wèn)。臨界區(qū)是指多個(gè)進(jìn)程或線程共享的內(nèi)存空間题篷,在訪問(wèn)臨界區(qū)的時(shí)候词身,多個(gè)進(jìn)程操作同一個(gè)資源,此時(shí)就存在競(jìng)態(tài)條件番枚,通常在兩個(gè)進(jìn)程對(duì)同一個(gè)資源寫(xiě)操作時(shí)法严,會(huì)產(chǎn)生結(jié)果不一致的問(wèn)題,因?yàn)槲覀儾恢老到y(tǒng)進(jìn)程何時(shí)切換葫笼,這種情況也很難復(fù)現(xiàn)和調(diào)試渐夸。必須有一種機(jī)制來(lái)保證在同一時(shí)刻只能有一個(gè)進(jìn)程訪問(wèn)臨界區(qū),信號(hào)量就提供了這種機(jī)制渔欢。

  2. 信號(hào)量是一種特殊的變量,程序?qū)λ脑L問(wèn)都是原子操作瘟忱,所謂原子操作奥额,即是指不可被中斷的操作,要實(shí)現(xiàn)原子操作單純軟件是不夠的访诱。雖然也能實(shí)現(xiàn)垫挨,但是效率很低,信號(hào)量是一種和硬件緊密結(jié)合的機(jī)制触菜,它不會(huì)被系統(tǒng)進(jìn)程切換和中斷操作打斷九榔。本文以二值信號(hào)量為例子,二值信號(hào)量能實(shí)現(xiàn)互斥鎖的功能,保證同一時(shí)間只能一個(gè)進(jìn)程訪問(wèn)資源哲泊。

  3. 信號(hào)量的P,V操作

    來(lái)自維基百科

計(jì)數(shù)信號(hào)量具備兩種操作動(dòng)作剩蟀,之前稱為 V(又稱signal())與 P(wait())。 V操作會(huì)增加信號(hào)量 S的數(shù)值切威,P操作會(huì)減少它育特。

運(yùn)作方式:

  1. 初始化,給與它一個(gè)非負(fù)數(shù)的整數(shù)值先朦。
  2. 運(yùn)行 P(wait())缰冤,信號(hào)量S的值將被減少。企圖進(jìn)入臨界區(qū)塊的進(jìn)程喳魏,需要先運(yùn)行 P(wait())棉浸。當(dāng)信號(hào)量S減為負(fù)值時(shí),進(jìn)程會(huì)被擋住刺彩,不能繼續(xù)迷郑;當(dāng)信號(hào)量S不為負(fù)值時(shí),進(jìn)程可以獲準(zhǔn)進(jìn)入臨界區(qū)塊迂苛。
  3. 運(yùn)行 V(又稱signal())三热,信號(hào)量S的值會(huì)被增加。結(jié)束離開(kāi)臨界區(qū)塊的進(jìn)程三幻,將會(huì)運(yùn)行 V(又稱signal())就漾。當(dāng)信號(hào)量S不為負(fù)值時(shí),先前被擋住的其他進(jìn)程念搬,將可獲準(zhǔn)進(jìn)入臨界區(qū)塊抑堡。

2、過(guò)程

  1. 獲取key值(同消息隊(duì)列)
  2. 獲取信號(hào)量ID(同消息隊(duì)列)
  3. semctl()函數(shù)初始化信號(hào)量
  4. fork()子進(jìn)程
  5. 執(zhí)行P,V操作

3朗徊、例子

sem.c 二值信號(hào)量

#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h> // 信號(hào)量函數(shù)庫(kù)
#include <unistd.h>

#define SEM_FILE "/Users/meetmax/CWork/sem_file" // 信號(hào)量文件

union sem_union //信號(hào)量聯(lián)合
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

//初始化信號(hào)量
int init_sem(int sem_id,int val)
{
    union sem_union tmp;
    tmp.val = val;
    if((semctl(sem_id,0,SETVAL,tmp)) == -1)
    {
        perror("初始化信號(hào)量失敗");
        return -1;
    }
    return 0;
}

/**
 * P操作
 * 信號(hào)量大于0時(shí)執(zhí)行 -1 操作首妖,獲取資源
 * 若信號(hào)量 <= 0 則掛起等待
*/
int sem_p(int sem_id)
{
    struct sembuf sbuf;
    sbuf.sem_num = 0;
    sbuf.sem_op = -1;
    sbuf.sem_flg = SEM_UNDO;
    if(semop(sem_id,&sbuf,1) == -1)
    {
        perror("p操作失敗");
        return -1;
    }
    return 0;
}

/**
 * V操作
 * 信號(hào)量 <= 0時(shí)執(zhí)行,+1操作爷恳,釋放資源
 * 若信號(hào)量 > 0 時(shí)掛起等待
 */
int sem_v(int sem_id)
{
    struct sembuf sbuf;
    sbuf.sem_num = 0;
    sbuf.sem_op = 1;
    sbuf.sem_flg = SEM_UNDO;
    if(semop(sem_id,&sbuf,1) == -1)
    {
        perror("V操作失敗");
        return -1;
    }
    return 0;
}

//刪除信號(hào)量
int sem_del(int sem_id)
{
    union sem_union tmp;
    if(semctl(sem_id,0,IPC_RMID,tmp) == -1)
    {
        perror("刪除信號(hào)量失敗");
        return -1;
    }
    return 0;
}

int main()
{
    int sem_id;
    key_t key;
    pid_t pid;

    //獲取key值
    if((key = ftok(SEM_FILE,100)) == -1)
    {
        perror("獲取key值失敗");
        exit(1);
    }
    //獲取信號(hào)量id
    if((sem_id = semget(key,1,IPC_CREAT|0666)) == -1)
    {
        perror("信號(hào)量id獲取失敗");
        exit(1);
    }

    //初始化信號(hào)量
    init_sem(sem_id,0);

    //fork進(jìn)程
    if((pid = fork()) == -1)
    {
        perror("進(jìn)程fork失敗");
        exit(1);
    }else if(pid == 0){ //子進(jìn)程
        printf("我是子進(jìn)程:%d \n",getpid());
        sleep(2);
        sem_v(sem_id);
    }else if(pid > 0){ //父進(jìn)程
        sem_p(sem_id);
        printf("我是父進(jìn)程:%d \n",getpid());
        sem_v(sem_id);
        sem_del(sem_id);
    }
    return 0;
}

四有缆、共享內(nèi)存

1、特點(diǎn)

概念

顧名思義温亲,共享內(nèi)存就是允許兩個(gè)不相關(guān)的進(jìn)程訪問(wèn)同一個(gè)邏輯內(nèi)存棚壁。共享內(nèi)存是在兩個(gè)正在運(yùn)行的進(jìn)程之間共享和傳遞數(shù)據(jù)的一種非常有效的方式。不同進(jìn)程之間共享的內(nèi)存通常安排為同一段物理內(nèi)存栈虚。進(jìn)程可以將同一段共享內(nèi)存連接到它們自己的地址空間中袖外,所有進(jìn)程都可以訪問(wèn)共享內(nèi)存中的地址,就好像它們是由用C語(yǔ)言函數(shù)malloc分配的內(nèi)存一樣魂务。而如果某個(gè)進(jìn)程向共享內(nèi)存寫(xiě)入數(shù)據(jù)曼验,所做的改動(dòng)將立即影響到可以訪問(wèn)同一段共享內(nèi)存的任何其他進(jìn)程泌射。

2、過(guò)程

  1. ftko()獲取key值(同消息隊(duì)列)
  2. shmget()函數(shù)獲取共享內(nèi)存ID
  3. 進(jìn)程通過(guò)shmat()函數(shù)連接共享內(nèi)存
  4. 訪問(wèn)共享內(nèi)存

3鬓照、示例

shm_server.c 讀數(shù)據(jù)

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <string.h>

#define SHM_FILE "/Users/meetmax/CWork/shm_file"

int main()
{
    int shm_id;
    key_t key;
    char * shm;
    struct shmid_ds buf;
    // 獲取key
    if((key = ftok(SHM_FILE,100)) == -1)
    {
        perror("獲取key失敗");
        exit(0);
    }
    // 獲取共享內(nèi)存描述符ID
    if((shm_id = shmget(key,512,IPC_CREAT|0666)) == -1)
    {
        perror("獲取共享內(nèi)存id失敗");
        exit(0);
    }
    // 連接共享內(nèi)存
    if((int)(shm = (char *)shmat(shm_id,0,0)) == -1)
    {
        perror("連接共享內(nèi)存失敗");
        exit(1);
    }
    printf("開(kāi)始接收數(shù)據(jù)\n");
  
    // 開(kāi)始忙等熔酷,接收數(shù)據(jù)
    while(1)
    {
        if(strlen(shm) > 0){
            printf("收到數(shù)據(jù):%s \n",shm);
            sprintf(shm,"");
        }
        if(strcmp(shm,"r") == 0){
            printf("已退出\n");
            break;
        }
    }
    // 刪除共享內(nèi)存
    shmctl(shm_id,IPC_RMID,&buf);
    return 0;

}

sem_client.c 寫(xiě)入數(shù)據(jù)

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>

#define SHM_FILE "/Users/meetmax/CWork/shm_file"

int main()
{
    int shm_id;
    key_t key;
    char * shm;
   
    // 獲取key
    if((key = ftok(SHM_FILE,100)) == -1)
    {
        perror("獲取key失敗");
        exit(0);
    }
    // 獲取共享內(nèi)存id
    if((shm_id = shmget(key,512,IPC_CREAT|0666)) == -1)
    {
        perror("獲取共享內(nèi)存id失敗");
        exit(0);
    }
    // 連接共享內(nèi)存,若不存在則創(chuàng)建
    if((int)(shm = (char *)shmat(shm_id,0,0)) == -1)   
    {
        perror("連接共享內(nèi)存失敗");
        exit(1);
    }
    printf("請(qǐng)輸入:");
    scanf("%s",shm); // 寫(xiě)入數(shù)據(jù)到共享內(nèi)存
    shmdt(shm); // 斷開(kāi)連接
    return 0;
}

參考

  • 《UNIX環(huán)境高級(jí)編程》
  • 《UNIX網(wǎng)絡(luò)編程:卷2》
  • 部分來(lái)自互聯(lián)網(wǎng)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颖杏,一起剝皮案震驚了整個(gè)濱河市纯陨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌留储,老刑警劉巖翼抠,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異获讳,居然都是意外死亡阴颖,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門丐膝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)量愧,“玉大人,你說(shuō)我怎么就攤上這事帅矗≠怂啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵浑此,是天一觀的道長(zhǎng)累颂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)凛俱,這世上最難降的妖魔是什么紊馏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮蒲犬,結(jié)果婚禮上朱监,老公的妹妹穿的比我還像新娘。我一直安慰自己原叮,他們只是感情好赫编,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著奋隶,像睡著了一般沛慢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上达布,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音逾冬,去河邊找鬼黍聂。 笑死躺苦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的产还。 我是一名探鬼主播匹厘,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼脐区!你這毒婦竟也來(lái)了愈诚?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤牛隅,失蹤者是張志新(化名)和其女友劉穎炕柔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體媒佣,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匕累,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了默伍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欢嘿。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖也糊,靈堂內(nèi)的尸體忽然破棺而出炼蹦,到底是詐尸還是另有隱情,我是刑警寧澤狸剃,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布掐隐,位于F島的核電站,受9級(jí)特大地震影響捕捂,放射性物質(zhì)發(fā)生泄漏瑟枫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一指攒、第九天 我趴在偏房一處隱蔽的房頂上張望慷妙。 院中可真熱鬧,春花似錦允悦、人聲如沸膝擂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)架馋。三九已至,卻和暖如春全闷,著一層夾襖步出監(jiān)牢的瞬間叉寂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工总珠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屏鳍,地道東北人勘纯。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像钓瞭,于是被迫代替她去往敵國(guó)和親驳遵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359