進程間通訊---共享內存(shmget)

固然只有mmap是能夠的,不過因爲各類不一樣的系統的架構不同,後來又通過整合,因此咱們如今的linux有多種內存共享方案,下面在介紹一種很是經常使用的系統V內存方案。
本人首先再在上次的基礎之上介紹一個網址
(國防科大的仁兄)
本人在本身理解的基礎上一步一步去深刻
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
  int shmid;
  char *shmadd;
  struct shmid_ds shmbuf;
  
   if((shmid=shmget(IPC_PRIVATE,1000,0666))<0)
    {perror( "shmget"); exit(1);}
   else printf( "created shared-memory: %d\n",shmid);
  system( "ipcs -m");
    
   if((shmadd=shmat(shmid,0,0))<(char *)0)
    { perror( "shmat"); exit(1); }
   else printf( "attached shared-memory\n");
  system( "ipcs -m");
  
   if((shmdt(shmadd))<0) //禁止本進程再使用該共享內存區
    {perror( "shmdt"); exit(1);}
   else printf( "deleted shared-memory\n");
  system( "ipcs -m");
   if(shmctl(shmid,IPC_RMID,&shmbuf)<0)
    {perror( "shmctl"); exit(1);}
  system( "ipcs -m");
  
  return 0;
}
shmget
int shmget(key_t key, size_t size, int flag);
key: 標識符的規則
size:共享存儲段的字節數
flag:讀寫的權限
返回值:成功返回共享存儲的id,失敗返回-1
shmat
void *shmat(int shmid, const void * addr, int flag);
shmid:共享存儲的id
addr:通常爲0,表示鏈接到由內核選擇的第一個可用地址上,不然,若是flag沒有指定SHM_RND,則鏈接到addr所指定的地址上,若是flag爲SHM_RND,則地址取整
flag:如前所述,通常爲0
返回值:若是成功,返回共享存儲段地址,出錯返回-1
shmdt
int shmdt(void *addr);
addr:共享存儲段的地址,之前調用shmat時的返回值
shmdt將使相關shmid_ds結構中的shm_nattch計數器值減1
shmctl
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid:共享存儲段的id
cmd:一些命令,有:IPC_STAT,IPC_RMID,SHM_LOCK,SHM_UNLOCK
程序說明:
結合我一些函數的說明,這個程序應該就很容易懂了,另外須要補充的是,查看共享內存段的命令式:ipcs -m,刪除共享內存段的命令是:ipcrm -m shmid,請注意,共享內存不會隨着程序結束而自動消除,要麼調用shmctl刪除,要麼本身用手敲命令去刪除,不然永遠留在系統中
另看
ipc_write.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct
{
        char name;
  int age;
}people;

int main(int argc,char **argv)
{
     int shm_id,i;
     key_t key;
     char temp_char;
     people *p_map;

     shm_id=shmget(IPC_PRIVATE,4096,IPC_CREAT);
     if(shm_id<0)
        {perror( "shmget error");return;}
     p_map=(people*)shmat(shm_id, NULL,0);
     temp_char= 'a';
     for(i=0;i<10;i++)
     {
        (*(p_map+i)).name=temp_char;
        (*(p_map+i)).age=20+i;    
        temp_char+=1;
     }
     if(shmdt(p_map)<0)
    perror( "detach error");
    
     return 0;
}
ipc_read.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct
{
        char name;
  int age;
}people;
int main(int argc,char **argv)
{
     int shm_id,i;
     key_t key;
     people *p_map;
     struct shmid_ds shmbuf;

     shm_id=393216;//393216是ipcs -m查看到的shmid
     p_map=(people*)shmat(shm_id, NULL,0);
     for(i=0;i<10;i++)
     {
        printf( "name----------%c\n",(*(p_map+i)).name);
        printf( "age------------%d\n",(*(p_map+i)).age);
     }
     if(shmdt(p_map)<0)
          perror( "shmdt error");
     if(shmctl(shm_id,IPC_RMID,&shmbuf)<0)
          perror( "shmctl error");
    
    return 0;
}
ipc_write.c實現向共享內存裏面寫,ipc_read.c實現從共享內存裏面讀
不過在ipc_write.c的shmget的第一個參數是IPC_PRIVATE,因此分配的key的值是
由系統產生的,而且沒有任何標誌獨特性的key_t的值。那麼ipc_read.c是如何知道shm_id的呢?我這個是本身手工查ipcs -m得來的,那麼編程中如何實現呢?
1.創建具備很是鮮明特徵,獨特的key值
2.經過信號量,消息隊列或者管道(FIFO)傳輸這個shm_id
shm_id也有人用,不過稍微麻煩一點,下面介紹用第一種方法
shm_ftok_write.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct
{
        char name;
  int age;
}people;

int main(int argc,char **argv)
{
     int shm_id,i;
     key_t key;
     char temp_char;
     people *p_map;
     char *name= "/dev/shm/myshm1";
    
     key = ftok(name,0);
     printf( "key=%d\n",key);
     if(key==-1)
                 perror( "ftok error");
     shm_id=shmget(IPC_PRIVATE,4096,IPC_CREAT);
                     printf( "shm_id=%d\n",shm_id);
     if(shm_id==-1)
        {perror( "shmget error");return;}
     p_map=(people*)shmat(shm_id, NULL,0);
     temp_char= 'a';
     for(i=0;i<10;i++)
     {
        (*(p_map+i)).name=temp_char;
        temp_char+=1;
        (*(p_map+i)).age=20+i;
     }
     if(shmdt(p_map)==-1)
    perror( "detach error");
    
     return 0;
}
ipc_ftok_read.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct
{
        char name;
  int age;
}people;
int main(int argc,char **argv)
{
     int shm_id,i;
     key_t key;
     people *p_map;
     char *name= "/dev/shm/myshm1";
    
     key = ftok(name,0);
     if(key==-1)
                 perror( "ftok error");
     shm_id=shmget(key,4096,IPC_CREAT);
                    printf( "shm_id=%d\n",shm_id);
     if(shm_id==-1)
        {perror( "shmget error");return;}
     p_map=(people*)shmat(shm_id, NULL,0);
     p_map=(people*)shmat(393216, NULL,0);
     for(i=0;i<10;i++)
     {
        printf( "name----------%c\n",(*(p_map+i)).name);
        printf( "age-----------%d\n",(*(p_map+i)).age);
     }
     if(shmdt(p_map)==-1)
    perror( "detach error");

    return 0;
}
這裏用的是獨特鮮明的key值
執行程序以前,先建立 "/dev/shm/myshm1"文件
最好是寫成本身的執行文件的目錄,如"/home/nsl/myprogram/ipc_ftok_write"這樣就不會存在文件不存在的狀況了
ftok
key_t ftok( char * fname, int id )
frame:文件的全路徑,要求文件存在且進程可訪問
id:第幾個共享內存
返回值:返回key值
註明:系統V共享內存與mmap相比,就是系統V共享內存歷來不把數據真正寫到磁盤文件中去,而mmap機制在munmap的時候將數據寫到磁盤文件
發現原來系統V共享內存也須要文件的支撐
固然,共享內存沒有這麼容易,還有大量的同步要作
再補充點共享內存的派系知識:
UNIX進程間通訊方式包括:管道、FIFO、信號。
System V進程間通訊方式包括:System V消息隊列、 System V信號燈、System V共享內存。
POSIX進程間通訊包括:posix消息隊列、posix信號 燈、posix共享內存。
我的以爲,mmap是posix共享內存
         shmget是System V共享內存
相關文章
相關標籤/搜索