/**
* 所有進程共用同一塊記憶體,共用記憶體在各種處理序間通訊方式中具有最高的效率。
* 訪問共用記憶體地區和訪問進程專屬的記憶體地區一樣快,並不需要通過系統調用或者其它需要切入核心的過程來完成
* 優缺:共用記憶體塊提供了在任意數量的進程之間進行高效雙向通訊的機制。每個使用者都可以讀取寫入資料,
* 但是所有程式之間必須達成並遵守一定的協議,以防止諸如在讀取資訊之前覆寫記憶體空間等競爭狀態的出現。
* 不幸的是,Linux無法嚴格保證提供對共用記憶體塊的獨佔訪問,甚至是在您通過使用IPC_PRIVATE建立新的共用記憶體塊的時候也不能保證訪問的獨佔性。
* 同時,多個使用共用記憶體塊的進程之間必須協調使用同一個索引值。(可通過訊號量來確保資料一致性)
*/
/*共用記憶體允許兩個或多個進程進程共用同一塊記憶體(這塊記憶體會映射到各個進程自己獨立的地址空間)
從而使得這些進程可以相互連信。
在GNU/Linux中所有的進程都有唯一的虛擬位址空間,而共用記憶體應用編程介面API允許一個進程使
用公用記憶體區段。但是對記憶體的共用訪問其複雜度也相應增加。共用記憶體的優點是簡易性。
使用訊息佇列時,一個進程要向隊列中寫入訊息,這要引起從使用者地址空間向核心地址空間的一次複製,
同樣一個進程進行訊息讀取時也要進行一次複製。共用記憶體的優點是完全省去了這些操作。
共用記憶體會映射到進程的虛擬位址空間,進程對其可以直接存取,避免了資料的複製過程。
因此,共用記憶體是GNU/Linux現在可用的最快速的IPC機制。
進程退出時會自動和已經掛接的共用記憶體區段分離,但是仍建議當進程不再使用共用區段時
調用shmdt來卸載區段。
注意,當一個進程分支出父進程和子進程時,父進程先前建立的所有共用記憶體區段都會被子進程繼承。
如果區段已經做了刪除標記(在前面以IPC——RMID指令調用shmctl),而當前掛接數已經變為0,
這個區段就會被移除。
*/
/*
shmget( ) 建立一個新的共用記憶體區段
取得一個共用記憶體區段的描述符
shmctl( ) 取得一個共用記憶體區段的資訊
為一個共用記憶體區段設定特定的資訊
移除一個共用記憶體區段
shmat( ) 掛接一個共用記憶體區段
shmdt( ) 於一個共用記憶體區段的分離
*/
//建立一個共用記憶體區段,並顯示其相關資訊,然後刪除該記憶體共用區
#include <stdio.h>
#include <unistd.h> //getpagesize( )
#include <sys/ipc.h>
#include <sys/shm.h>
#define MY_SHM_ID 67483
int main( )
{
//獲得系統中頁面的大小
printf( "page size=%d/n",getpagesize( ) );
//建立一個共用記憶體區段
int shmid,ret;
shmid=shmget( MY_SHM_ID,4096,0666|IPC_CREAT );
//建立了一個4KB大小共用記憶體區段。指定的大小必須是當前系統架構
//中頁面大小的整數倍
if( shmid>0 )
printf( "Create a shared memory segment %d/n",shmid );
//獲得一個記憶體區段的資訊
struct shmid_ds shmds;
//shmid=shmget( MY_SHM_ID,0,0 );//樣本怎樣獲得一個共用記憶體的標識符
ret=shmctl( shmid,IPC_STAT,&shmds );
if( ret==0 )
{
printf( "Size of memory segment is %d/n",shmds.shm_segsz );
printf( "Numbre of attaches %d/n",( int )shmds.shm_nattch );
}
else
{
printf( "shmctl( ) call failed/n" );
}
//刪除該共用記憶體區
ret=shmctl( shmid,IPC_RMID,0 );
if( ret==0 )
printf( "Shared memory removed /n" );
else
printf( "Shared memory remove failed /n" );
return 0;
}
//共用記憶體區段的掛載,脫離和使用
//理解共用記憶體區段就是一塊大記憶體
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <errno.h>
#define MY_SHM_ID 67483
int main( )
{
//共用記憶體區段的掛載和脫離
int shmid,ret;
void* mem;
shmid=shmget( MY_SHM_ID,0,0 );
if( shmid>=0 )
{
mem=shmat( shmid,( const void* )0,0 );
//shmat()返回進程地址空間中指向區段的指標
if( ( int )mem!=-1 )
{
printf( "Shared memory was attached in our address space at %p/n",mem );
//向共用區段記憶體寫入資料
strcpy( ( char* )mem,"This is a test string./n" );
printf( "%s/n",(char*)mem );
//脫離共用記憶體區段
ret=shmdt( mem );
if( ret==0 )
printf( "Successfully detached memory /n" );
else
printf( "Memory detached failed %d/n",errno );
}
else
printf( "shmat( ) failed/n" );
}
else
printf( "shared memory segment not found/n" );
return 0;
}