作業系統實驗筆記(六)-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);
}