1. 程式人生 > >程序間通訊 記憶體共享訊號量例項理解

程序間通訊 記憶體共享訊號量例項理解

申請記憶體:

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

其中key為鑰匙,兩程序通過同一個鑰匙找到核心中的共享記憶體,可通過

key_t ftok(const char *pathname, int proj_id)

得到key,也可通過強制轉換自行制定數值。
size為申請共享記憶體空間的大小(B)
shmflg為標誌
返回值為共享記憶體的標示符。

記憶體對映:

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

其中shmid為共享記憶體的ID。
shmaddr為映射向程序的地址,一般填NULL讓系統指配
返回值為程序內對映共享內粗的地址。

這樣通過操作程序內對映地址(記憶體),便可以在共享記憶體中寫入或讀取資料。


但該過程是不受控制的,因此我們需要通過阻塞來控制程序的執行。

訊號量

訊號量與共享記憶體類似,也是在核心空間中申請一段記憶體儲存資料

申請訊號量:

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

其中 key為鑰匙,兩程序通過鑰匙找到同一個訊號量
nsems 為申請的訊號量的個數
返回值為訊號量標示符

操作訊號量:

int semctl(int semid, int semnum, int cmd, ...);

其中semnum,為第semnum位訊號量,從0開始
cmd為指定的操作
後面跟對應資料

int semop(int semid, struct sembuf *sops, unsigned nsops);

其中

struct sembuf
{
      unsigned short sem_num;  /* 第sem_num位訊號量 */
      short sem_op;   /* 操作量 */
      short  sem_flg;  /* 標誌對應操作 */
}

nsops為,對nsops個訊號量進行該操作

因為訊號量的值不能小於0,因此可以通過semop函式進行阻塞。

例項:

輸入程式:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<sys/sem.h> #include<string.h> int main() { int running =1; int shid; int semid; int value; char *sharem=NULL; struct sembuf sem_b,sem_c; sem_b.sem_num=1; sem_b.sem_flg=SEM_UNDO; sem_c.sem_num=0; sem_c.sem_flg=SEM_UNDO; if((semid=semget((key_t)123456,2,0666|IPC_CREAT))==-1)//申請訊號量 { perror("semget"); exit(1); } shid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);//申請共享記憶體 if(shid==-1) exit(1); sharem=shmat(shid,NULL,0); if(sharem==NULL) exit(1); semctl(semid,1,SETVAL,1);//初始化將自己的訊號量設為1 semctl(semid,0,SETVAL,0);//將讀取程序的訊號量設為0使之堵塞 while(running) { sem_b.sem_op=-1;//設為-1 if(semop(semid,&sem_b,1)==-1)//讓訊號量0加-1,若此時訊號量為0則無法-1則阻塞 { exit(1); } printf("write data operate\n"); printf("please input something:"); scanf("%s",sharem); semctl(semid,0,SETVAL,1);//輸入完畢將讀取訊號訊號量置1使之不堵塞 semctl(semid,1,SETVAL,0);//將自己的訊號量設為0,使自身堵塞無法再寫入 if(strcmp(sharem,"end")==0) running--; } shmdt(sharem); return 0; }

接收程式:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<string.h>

int main()
{
    int running =1;
    int shid;
    int semid;
    int value;
    char *sharem=NULL;
    struct sembuf sem_b,sem_c;
    sem_b.sem_num=1;
    sem_b.sem_flg=SEM_UNDO;
    sem_c.sem_num=0;
    sem_c.sem_flg=SEM_UNDO;
    if((semid=semget((key_t)123456,2,0666|IPC_CREAT))==-1)
    {
        perror("semget");
        exit(1);
    }
    shid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);
    if(shid==-1)
        exit(1);
    sharem=shmat(shid,NULL,0);
    if(sharem==NULL)
        exit(1);
    semctl(semid,0,SETVAL,1);
    //初始化,使自己堵塞,等待輸入程序的輸入
    while(running)
    {
        sem_b.sem_op=-1;
        if(semop(semid,&sem_b,1)==-1)//同輸入程序
        {
            exit(1);
        }
        printf("read data operate\n");
        printf("%s\n",sharem);

        semctl(semid,0,SETVAL,0);//將輸入程序的訊號量置1
        semctl(semid,1,SETVAL,1);//將自己堵塞

        if(strcmp(sharem,"end")==0)
            running--;
    }
    shmdt(sharem);
    if(shmctl(shid,IPC_RMID,0)!=0)//銷燬共享記憶體
    {
        exit(1);
    }
    if(semctl(semid,0,IPC_RMID,0)!=0)//銷燬訊號量
    {
        exit(1);
    }
    return 0;

}