1. 程式人生 > >作業系統實驗筆記(六)-linux下共享儲存區通訊

作業系統實驗筆記(六)-linux下共享儲存區通訊

目錄

  • 前期基礎知識

  • 客戶端向伺服器端共享儲存區

  • 子程序之間共享儲存區

  • 前期基礎知識

    本次實驗其實重點的是這麼幾個變數:addr、shmid 以及幾個重要的函式:shmet、shmat、shmget、shmctl

對於系統V共享記憶體,主要有以下幾個API:shmget()、shmat()、shmdt()及shmctl()。

   #include<sys/ipc.h>

   #include<sys/shm.h>

   shmget()用來獲得共享記憶體區域的ID,如果不存在指定的共享區域就建立相應的區域。shmat()把共享記憶體區域對映到呼叫程序的地址空間中去,這樣,程序就可以方便地對共享區域進行訪問操作。shmdt()呼叫用來解除程序對共享記憶體區域的對映。shmctl實現對共享記憶體區域的控制操作。

注:shmget的內部實現包含了許多重要的系統V共享記憶體機制;shmat在把共享記憶體區域對映到程序空間時,並不真正改變程序的頁表。當程序第一次訪問記憶體對映區域訪問時,會因為沒有物理頁表的分配而導致一個缺頁異常,然後核心會根據相應的儲存管理機制為共享記憶體對映區域分配相應的頁表。

    應當指出,共享儲存區機制只為程序提供了用於實現通訊的共享儲存區和對共享儲存區進行操作的手段,然而並未提供對該區進行互斥訪問及程序同步的措施。因而當用戶需要使用該機制時,必須自己設定同步和互斥措施才能保證實現正確的通訊。

涉及的系統呼叫

1、shmget( )

建立、獲得一個共享儲存區。

系統呼叫格式:

        shmid=shmget(key,size,flag)

該函式使用標頭檔案如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

引數定義

         int  shmget(key,size,flag);

         key_t  key;

         int  size,flag;

其中,key是共享儲存區的名字;size是其大小(以位元組計);flag是使用者設定的標誌,如IPC_CREAT。IPC_CREAT表示若系統中尚無指名的共享儲存區,則由核心建立一個共享儲存區;若系統中已有共享儲存區,便忽略IPC_CREAT。

附:

        操作允許權                  八進位制數

         使用者可讀                     00400

         使用者可寫                     00200

         小組可讀                     00040

         小組可寫                     00020

         其它可讀                     00004

         其它可寫                     00002

控制命令                    值

IPC_CREAT                0001000

IPC_EXCL                0002000

例:shmid=shmget(key,size,(IPC_CREAT|0400))

     建立一個關鍵字為key,長度為size的共享儲存區

2、shmat( )

    共享儲存區的附接。從邏輯上將一個共享儲存區附接到程序的虛擬地址空間上。

系統呼叫格式:

                virtaddr=shmat(shmid,addr,flag)

該函式使用標頭檔案如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

引數定義

         char  *shmat(shmid,addr,flag);

         int  shmid,flag;

         char  * addr;

其中,shmid是共享儲存區的識別符號;addr是使用者給定的,將共享儲存區附接到程序的虛地址空間;flag規定共享儲存區的讀、寫許可權,以及系統是否應對使用者規定的地址做舍入操作。其值為SHM_RDONLY時,表示只能讀;其值為0時,表示可讀、可寫;其值為SHM_RND(取整)時,表示作業系統在必要時捨去這個地址。該系統呼叫的返回值是共享儲存區所附接到的程序虛地址viraddr。

3、shmdt( )

把一個共享儲存區從指定程序的虛地址空間斷開。

系統呼叫格式:

             shmdt(addr)

該函式使用標頭檔案如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

引數定義

         int  shmdt(addr);

         char  addr;

其中,addr是要斷開連線的虛地址,亦即以前由連線的系統呼叫shmat( )所返回的虛地址。呼叫成功時,返回0值,呼叫不成功,返回-1。 值得注意的是: 這裡的addr我們可以用於存資料

4、shmctl( )

共享儲存區的控制,對其狀態資訊進行讀取和修改。

系統呼叫格式:

              shmctl(shmid,cmd,buf)

該函式使用標頭檔案如下:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/shm.h>

引數定義

             int  shmctl(shmid,cmd,buf);

             int shmid,cmd;

             struct shmid_ds  *buf;

其中,buf是使用者緩衝區地址,cmd是操作命令。命令可分為多種型別:

(1)用於查詢有關共享儲存區的情況。如其長度、當前連線的程序數、共享區的建立者識別符號等;

(2)用於設定或改變共享儲存區的屬性。如共享儲存區的許可權、當前連線的程序計數等;

(3)對共享儲存區的加鎖和解鎖命令;

(4)刪除共享儲存區識別符號等。

    上述的查詢是將shmid所指示的資料結構中的有關成員,放入所指示的緩衝區中;而設定是用由buf所指示的緩衝區內容來設定由shmid所指示的資料結構中的相應成員。

cmd有下列幾種數值:

IPC_STAT         把共享記憶體的

IPC_SET          將引數buf所指的shmid_ds 結構中的shm_perm.uid、shm_perm.gid和shm_perm.mode複製到共享記憶體的shmid_ds結構內。

IPC_RMID         刪除共享記憶體和資料結構。

SHM_LOCK       不讓此共享記憶體置換到swap。

SHM_UNLOCK    允許此gon共享記憶體置換到swap。

SHM_LOCK 和SHM_UNLOCK為LUNIX特有,且唯有超級使用者(root)允許使用



  • 客戶端向伺服器端共享儲存區

為了方便除錯我還是覺得直接將客戶端與伺服器端作為了函式進行了呼叫,這位我們第三個實驗簡化了步驟

#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define  SHMKEY  75
int  shmid,i;   int  *addr;

void  client( )
{  int i=0;
       shmid=shmget(SHMKEY,1024,0777);      /*開啟共享儲存區*/
addr=shmat(shmid,0,0);           /*獲得共享儲存區首地址*/
for (i=9;i>=0;i--)
  {  while (*addr!=-1);
     printf("(client) sent\n");
     *addr=i;
 }
exit(0);
}

void  server( )
{
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*建立共享儲存區*/
addr=shmat(shmid,0,0);        /*獲取首地址*/
do 
 {
     *addr=-1;
     while (*addr==-1);
     printf("(server) received\n");
}while (*addr);
shmctl(shmid,IPC_RMID,0);     /*撤消共享儲存區,歸還資源*/
exit(0);
}

main( )
{
   while ((i=fork( ))==-1);
   if (!i) server( );
   while ((i=fork( ))==-1);
   if (!i) client( );
   wait(0);
   wait(0);
}

  • 子程序之間共享儲存區


#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define  SHMKEY  75
int  shmid,i;   int  *addr;


void  shmw( )
{  int i=0;
       shmid=shmget(SHMKEY,1024,0777);      /*開啟共享儲存區*/
addr=shmat(shmid,0,0);           /*獲得共享儲存區首地址*/
for (i=9;i>=0;i--)
  {  while (*addr!=-1);
     printf("(write) is  \n");
     *addr=i;
 }
exit(0);
}


void  shmr( )
{
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*建立共享儲存區*/
addr=shmat(shmid,0,0);        /*獲取首地址*/
do 
 {
     *addr=-1;
     while (*addr==-1);
     printf("(read) ok is ");
     printf("%d\n",*addr);
}while (*addr);
shmctl(shmid,IPC_RMID,0);     /*撤消共享儲存區,歸還資源*/
exit(0);
}

main( )
{
   while ((i=fork( ))==-1);
   if (!i) shmr( );
   while ((i=fork( ))==-1);
   if (!i) shmw( );
   wait(0);
   wait(0);
}