IPC-共享內存

進程間通信的三大主題纖消息隊列、信號量、共享內存,還剩下最後一個模塊。下來我們就來看看這最後一個主題:共享內存。

共享內存

共享內存允許兩個或多個進程共享一個給定的存儲區。因爲共享內存數據不需要在進程和進程之間複製,所以共享內存是最快的一種IPC。
允許兩個或多個進程共享一個存儲區的意思是,同一塊物理內存被映射到這些進程各自的進程地址空間。這樣這些進程都可以看到其他進程對共享內存中數據的更新。
另外要注意的是共享內存和管道不同,共享內存不提供互斥與同步機制,所以當一個進程正在將數據放入共享內存中,那麼其他進程在它做完這一操作之前,不應該對共享內存進行數據寫入。通常通過信號量和互斥鎖實現互斥與同步。

共享內存相關函數

  • shmget:創建共享內存
 #include <sys/shm.h>
 int shmget(key_t key, size_t size, int shmflg);
    返回值:若成功,返回共享內存ID,若出錯,返回-1

key和shmflg就不說了和前面創建其他IPC機制一樣。
需要知道的是參數size,這裏的size是共享內存段的長度,以字節爲單位,而操作系統爲你分配空間的時候是按照頁來分配的,所以size應該爲4k(一般一頁的大小)的整數倍。若size值不是整數倍,那麼最後一頁的餘下部分是不可使用的。

  • shmat: 連接共享內存
    一旦創建了一個共享內存,進程就可調用shmat將其連接到它的地址空間中。
 #include <sys/shm.h>
 void *shmat(int shmid, const void *shmaddr, int shmflg);
 返回值:若成功,返回指向共享內存的指針;若出錯,返回-1

shmid是共享內存ID
共享內存段連接到調用進程的哪個地址上與addr以及shmflg有關。
一般addr設置爲NULL,shmflg設置爲0就可以了。

  • shmdt:去關聯共享內存
    當對共享內存段的操作已經結束時,則調用shmdt與該段分離。注意,這並不是從系統中刪除其標識符以及相關數據結構。該標識符仍然存在,知道某進程自己進行刪除
  #include <sys/shm.h>
  int shmdt(const void *shmaddr);
  返回值:若成功,返回0,若出錯,返回-1

shmaddr參數是shmat的返回值。如果成功,shmat將使相關shmid_ds數據結構中的shm_nattch計數器減1。

  • shmctl:對共享內存段執行多種操作(刪除、取shmid_ds結構、加鎖、解鎖等)
 #include <sys/shm.h>
 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
 返回值:若成功,返回0;若出錯,返回-1

cmd:參數指定5種命令中的一種。最重要的就是刪除命令IPC_RMID。
buf:如果不需要取此段的shmid_ds就直接NULL就行了。

程序實例:

- shm.h

/*************************************************************************

    > File Name: shm.h

    > Author: 

    > Mail: 

    > Created Time: Tue 13 Jun 2017 05:46:14 AM PDT

 ************************************************************************/

#include<stdio.h>

#include<unistd.h>

#include<sys/shm.h>

#include<sys/ipc.h>

#include<sys/wait.h>

#define __PATH__ "."

#define __PROJECT__ 8888

#define __SHM_SIZE__ 4*1024 //4k對齊

//創建共享存儲區

int common_shm(int flag)

{

   int key=ftok(__PATH__,__PROJECT__);

    if(key==-1)

    {

        printf("ftok is faild!\n");

        return -1;

    }

    return shmget(key,__SHM_SIZE__,flag);

}

int creat_shm()

{

    return common_shm(IPC_CREAT|0666);

}

int get_shm()

{

    return common_shm(0);

}

//連接已有的共享內存

void *at_shm(int shmid)

{

    return (char*)shmat(shmid,NULL,0);   

}

//進程與共享內存分離

int dt_shm(const void *addr)

{

    return shmdt(addr);

}

//刪除共享內存

int destory_shm(int shmid)

{

    return shmctl(shmid,IPC_RMID,NULL);

}
  • client.c
/*************************************************************************

    > File Name: client.c

    > Author: 

    > Mail: 

    > Created Time: Tue 13 Jun 2017 06:16:21 AM PDT

 ************************************************************************/
#include"shm.h"
int main()
{
    int shmid=get_shm();
    if(shmid==-1)
    {
        printf("get_shm is faild!\n");
    }
    char *addr=at_shm(shmid);
    sleep(1);
   int i = 0;
   while(1)
        {
           sleep(1);
            addr[i++] = 'a';
            i %= (__SHM_SIZE__-1);
            addr[i]='\0';
        }
    dt_shm(addr);
    return 0;
}
  • server.c
/*************************************************************************

    > File Name: server.c

    > Author: 

    > Mail: 

    > Created Time: Tue 13 Jun 2017 06:50:10 AM PDT

 ************************************************************************/

#include"shm.h"

int main()

{

    int shmid=creat_shm();

    if(shmid==-1)

    {

        printf("creat_shm is faild!\n");

        return -1;

    }

    sleep(5);

    char *addr=at_shm(shmid);

    while(1)

    {

        sleep(1);

        printf("%s\n",addr);

    }

    sleep(5);

    dt_shm(addr);

    destory_shm(shmid);

    return 0;

}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章