共享內存是UNIX提供的進程間通信手段中速度最快的一種,也是最快的IPC形式。為什么是最快的呢,因為數據不需要在客戶進程和服務器進程之間復制,所以是最快的一種IPC。這是虛存中由多個進程共享的一個公共內存塊。
兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。
如果服務器進程正在將數據放入到共享存儲區,則在它做完這一操作之前,客戶進程不應當去取這些數據。通常信號量用于同步共享存儲訪問。
由于共享內存是通過映射到同一塊物理內存后進行的通信,因此肯定需要映射到內存的函數和解除映射的函數,主要有以下幾種
#define SHMAT 21//空間映射:把上面打開的內存區域連接到用戶的進程空間中
#define SHMDT 22//解除映射:將共享內存從當前進程中分離
#define SHMGET 23//創建打開一個內存區域
#define SHMCTL 24//內存區域的控制:包括初始化和刪除內存區域。
注意:共享內存通信本身沒有提供同步機制,如果同時被多個進程進行映射和寫操作,會導致破壞該內存空間的內容。因此在實際應用過程中,需要通過其他的機制來同步對共享內存的訪問。比如信號量。
內核為每個共享存儲段維護著一個結構,該結構至少要為每個共享存儲段包含以下成員:
struct shmid_ds
{struct ipc_perm shm_perm; size_t shm_segsz; pid_t shm_lpid; pid_t shm_cpid; shmatt_t shm_nattch; time_t shm_atime; time_t shm_dtime; time_t shm_ctime;
};
1.調用的第一個函數為shmget:
#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
2.shmctl函數對共享內存段執行多種操作
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
3.一旦創建了共享存儲段,進程就可調用shmat將其連接到它的地址空間中。
void *shmat(int shmid,const void * addr,int flag);
int shmdt(const void * addr);
具體代碼實現:
#ifndef _COMM_H_
#define _COMM_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h> #define PATHNAME "."
#define PROJ_ID 0X6667 int CreateShm(int size);
int GetShm(int size);int destroyShm(int shmid);#endif //_COMM_H_
#include"comm.h" int CommShm(int size ,int flags)
{key_t key = ftok(PATHNAME,PROJ_ID);if (key < 0 ){perror("ftok" );return -1 ;}int shmid = shmget(key,size ,flags); if (shmid < 0 ){perror("shmget" );return -2 ;}return shmid;
}int CreateShm(int size )
{return CommShm(size ,IPC_CREAT|IPC_EXCL|0666 );
}
int GetShm(int size )
{return CommShm(size ,IPC_CREAT);
}
int destroyShm(int shmid)
{if (shmctl(shmid,IPC_RMID,NULL) < 0 ){perror("shmctl" );return -1 ;}return 0 ;
}
#include"comm.h" int main()
{int shmid = CreateShm(4096 );
char *addr = shmat(shmid,NULL ,0 );if (addr == NULL ){return 1 ;}int i = 0 ;char s = 'a' ;while (1 ){addr[i] = s;s++;}addr[i] = 0 ;sleep(4 );shmdt(addr);printf("shm quit!\n" );return 0 ;
}
//client.c
int main()
{int shmid = GetShm(4096 );//printf ("hello client!\n" );char *addr = shmat(shmid,NULL,0 );if (addr == NULL)return 2 ;printf ("%s " ,addr);sleep (10 );shmdt(addr); printf ("shm quit!\n" );return 0 ;
}
運行結果: