共享內存

關於建立共享內存的相關函數

建立共享內存的目的在於實現進程間數據段的共享。

 

一:共享內存建立及相關函數

 

1、共享內存的使用步驟

1.1.開闢一塊共享內存 shmget()
1.2.允許本進程使用共某塊共享內存 shmat()
1.3.寫入/讀出
1.4.禁止本進程使用這塊共享內存 shmdt()
1.5.刪除這塊共享內存 shmctl()或者命令行下ipcrm

 

2、共享內存的建立

int shmget(key_t key, size_t size, int shmflg);

key:建立共享內存的鍵值,該值是可以自己設定的,當有信號量時,該值是信號量返回的鍵值。

size:建立共享內存的大小;

shmflg:建立共享內存的權限。如:0666 | IPC_CREAT

返回建立共享內存的描述符。

 

3、共享內存的獲取

void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:shmget()函數返回的共享內存的描述符。

shmaddr:是共享內存的起始地址,可以爲空。
shmflag:是本進程對該內存的操作模式。如果是SHM_RDONLY的話,就是隻讀模式。其它的是讀寫模式
成功時,這個函數返回共享內存的起始地址。失敗時返回-1。

 

4、共享內存的禁用

int shmdt(const void *shmaddr);

shmdt()與shmat()相反,是用來禁止本進程訪問一塊共享內存的函數。
參數char *shmaddr是那塊共享內存的起始地址。
成功時返回0。失敗時返回-1。

 

5、共享內存的刪除

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:共享內存描述符

cmd:操作共享內存的命令

IPC_STAT 得到共享內存的狀態
IPC_SET 改變共享內存的狀態
IPC_RMID 刪除共享內存

buf:IPC_STAT的時候,取得的狀態放在這個結構體中。如果要改變共享內存的狀態,用這個結構體指定.

 

二、共享內存信號量

建立共享內存後,各個進程可能會對共享內存同時操作,爲了保證各個進程正常的使用共享內存,採用信號量,保證各個進程間有序的使用共享內存。

 

1、生成信號量描述符

key_t ftok(const char *pathname, int proj_id);

pathname: 一般用當前進程的程序名

proj_id:標記這個標識符所標識的共享內存是這個進程所開闢的第幾個共享內存

ftok()會返回一個key_t型的值,也就是計算出來的標識符的值。

 

2、信號量的獲取

int semget(key_t key, int nsems, int semflg);

key:ftok()函數創建的鍵值

nsems:建立信號量的個數

semflg:建立信號量的標誌。如:IPC_EXCL | IPC_CREAT | 0660

返回值:如果成功,則返回信號量集的IPC標識符。如果失敗,則返回-1:errno=EACCESS(沒有權限)
EEXIST(信號量集已經存在,無法創建)
EIDRM(信號量集已經刪除)
ENOENT(信號量集不存在,同時沒有使用IPC_CREAT)
ENOMEM(沒有足夠的內存創建新的信號量集)
ENOSPC(超出限制)

 

2、信號量的操作

int semop(int semid,struct sembuf*sops,unsign ednsops);
semid:semget()返回的描述符

sops:指向將要操作的數組的指針

ednsops:數組中的操作的個數。

struct sembuf

{
     ushort  sem_num;     /*semaphore index in array*/
     short    sem_op;        /*semaphore operation*/
     short    sem_flg;       /*operation flags*/

}
sem_num將要處理的信號量的個數。
sem_op要執行的操作。
sem_flg操作標誌。

如果sem_op是負數,那麼信號量將減去它的值.如果sem_op是正數,則信號量加上它的值.如果sem_op是0,那麼調用進程將調用sleep(),直到信號量的值爲0。這在一個進程等待完全空閒的資源時使用。

。如果沒有使用IPC_NOWAIT,那麼調用進程將進入睡眠狀態,直到信號量控制的資源可以使用爲止。

返回值:

0,如果成功。-1,如果失敗:errno=E2BIG(nsops大於最大的ops數目)
EACCESS(權限不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續進行)
EFAULT(sops指向的地址無效)
EIDRM(信號量集已經刪除)
EINTR(當睡眠時接收到其他信號)
EINVAL(信號量集不存在,或者semid無效)
ENOMEM(使用了SEM_UNDO,但無足夠的內存創建所需的數據結構)
ERANGE(信號量值超出範圍)

 

3、信號量的控制

int semctl(int semid,int semnum,int cmd,union semunarg);
semid:獲取的信號量的id;

semnum:在信號量中的位置

cmd:控制命令

     IPC_STAT讀取一個信號量集的數據結構semid_ds,並將其存儲在semun中的buf參數中。
    ·IPC_SET設置信號量集的數據結構semid_ds中的元素ipc_perm,其值取自semun中的buf參數。
    ·IPC_RMID將信號量集從內存中刪除。
    ·GETALL用於讀取信號量集中的所有信號量的值。
    ·GETNCNT返回正在等待資源的進程數目。
    ·GETPID返回最後一個執行semop操作的進程的PID。
    ·GETVAL返回信號量集中的一個單個的信號量的值。
    ·GETZCNT返回這在等待完全空閒的資源的進程數目。
    ·SETALL設置信號量集中的所有的信號量的值。
    ·SETVAL設置信號量集中的一個單獨的信號量的值。

semunarg:表示設定的值。

例子:

int get_sem_val(intsid,intsemnum)
{
     return(semctl(sid,semnum,GETVAL,0));
}
 下面是一個實際應用的例子:
#defineMAX_PRINTERS5
printer_usage()
{
      int x;
      for(x=0;x<MAX_PRINTERS;x++)
      printf("Printer%d:%d/n/r",x,get_sem_val(sid,x));
}
下面的程序可以用來初始化一個新的信號量值:
void init_semaphore(int sid,int semnum,int initval)
{
     union semunsemopts;
     semopts.val=initval;
     semctl(sid,semnum,SETVAL,semopts);
}

 

例子上傳。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章