linux程式間通訊-----System V共享記憶體總結例項

readyao發表於2015-12-21

共享記憶體簡介

共享記憶體區是最快的IPC形式。一旦這樣的記憶體對映到共享它的程式的地址空間,這些程式間資料傳遞不再涉及到核心,換句話說是程式不再通過執行進入核心的系統呼叫來傳遞彼此的資料。

程式1對映到該共享記憶體區域後,就可以通過對映之後得到的首地址p1,直接對那一片共享記憶體區域進行操作;
程式2對映到同一塊記憶體區域後,也可以得到對映之後的那一片共享記憶體的首地址p2,通過p2可以直接對那一片共享記憶體區域進行操作;

System V共享記憶體API

1:建立共享記憶體

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
key:這個共享記憶體段名字,可以自己指定,也可以通過ftok函式來生成一個隨機的key
size:共享記憶體大小
shmflg:由九個許可權標誌構成,它們的用法和建立檔案時使用的mode模式標誌是一樣的
返回值:成功返回一個非負整數,即該共享記憶體段的標識碼;失敗返回-1
ret = shmget(0x2234, sizeof(Teacher), 0666 | IPC_CREAT);//存在就使用舊的 不存在就建立

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);//隨機產生key值


2:將共享記憶體段連線到程式地址空間

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid: 共享記憶體標識,就是函式shmget的返回值
shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一個指標,指向共享記憶體第一個節;失敗返回-1

shmaddr:指定連線的地址
shmaddr為NULL,核心自動選擇一個地址
shmaddr不為NULL且shmflg無SHM_RND標記,則以shmaddr為連線地址。
shmaddr不為NULL且shmflg設定了SHM_RND標記,則連線的地址會自動向下調整為SHMLBA的整數倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示連線操作用來只讀共享記憶體

3:將共享記憶體段與當前程式脫離
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
shmaddr: 由shmat所返回的指標
返回值:成功返回0;失敗返回-1
注意:將共享記憶體段與當前程式脫離不等於刪除共享記憶體段

4:用於控制共享記憶體

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:由shmget返回的共享記憶體標識碼
cmd:將要採取的動作(有三個可取值)
buf:指向一個儲存著共享記憶體的模式狀態和訪問許可權的資料結構
返回值:成功返回0;失敗返回-1

IPC_STAT:獲得共享記憶體資料結構的資訊
IPC_SET :設定共享記憶體資料結構的資訊
IPC_RMID:刪除共享記憶體段
 struct shmid_ds {
     struct ipc_perm shm_perm;    /* Ownership and permissions */
     size_t          shm_segsz;   /* Size of segment (bytes) */
     time_t          shm_atime;   /* Last attach time */
     time_t          shm_dtime;   /* Last detach time */
     time_t          shm_ctime;   /* Last change time */
     pid_t           shm_cpid;    /* PID of creator */
     pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
     shmatt_t        shm_nattch;  /* No. of current attaches */
     ...
 };

The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):

 struct ipc_perm {
     key_t          __key;    /* Key supplied to shmget(2) */
     uid_t          uid;      /* Effective UID of owner */
     gid_t          gid;      /* Effective GID of owner */
     uid_t          cuid;     /* Effective UID of creator */
     gid_t          cgid;     /* Effective GID of creator */
     unsigned short mode;     /* Permissions + SHM_DEST and
                                 SHM_LOCKED flags */
     unsigned short __seq;    /* Sequence number */
 };

例項1:

程式1建立鍵值是0x1111的共享記憶體,大小為1024位元組;程式1從標準輸入讀入資料並寫入到共享記憶體中;當程式1輸入over的時候,刪除該共享記憶體,並退出;
程式2開啟鍵值是0x1111的共享記憶體,並從裡面讀取資料然後輸出到標準輸出上面;當程式2收到over之後退出;
備註:當兩個程式都執行的時候,輸入命令ipcs可以看到鍵值是0x1111的共享記憶體的連線數是2,也就是說有兩個程式已經連線到了該共享記憶體區域;

write_shm.cpp

/*************************************************************************
	> File Name: write_shm.cpp
	> Author: 
	> Mail: 
	> Created Time: 2015年12月21日 星期一 11時15分23秒
 ************************************************************************/

#include <iostream>
#include <cstdlib>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
using namespace std;

/*
1: 建立一塊共享記憶體
2:連線到共享記憶體,並向共享記憶體中寫入資料
3:脫離該共享記憶體區域
*/
#define SHMSIZE 1024

int main(int argc, char *argv[])
{
    /*
    if(argc < 2){
        cout << "input the pathname fo generate key..."<< endl;
        exit(-1);
    }*/
    key_t key = 0x1111;//ftok(argv[1], 'a');
    
    int shmid = shmget(key, SHMSIZE, 0666|IPC_CREAT);
    if(shmid == -1){
        cerr << "shmget error ...." << endl;
        exit(-1);
    }

    char * p = (char *)shmat(shmid, NULL, 0);
    pid_t pid = getpid();
    cout << "process " << pid << " write: ";
    while(cin.getline(p, SHMSIZE)){
        if(strcmp(p, "over") == 0){
            break;
        }
        cout << "process " << pid << " write: ";
    }
//脫離該共享記憶體區域,並刪除該共享記憶體區域
    shmdt(p);
    shmctl(shmid, IPC_RMID, NULL);
    cout << "已經刪除了共享記憶體,並退出。\n";
    exit(0);
}

read_shm.cpp

/*************************************************************************
	> File Name: read_shm.cpp
	> Author: 
	> Mail: 
	> Created Time: 2015年12月21日 星期一 11時15分23秒
 ************************************************************************/

#include <iostream>
#include <cstdlib>
#include <sys/ipc.h>
#include <string.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/types.h>
using namespace std;

/*
連線到共享記憶體,並向共享記憶體中讀入資料
脫離該共享記憶體區域
*/
#define SHMSIZE 1024

int main(int argc, char *argv[])
{
    key_t key = 0x1111; 
   //當共享記憶體中有資料的時候它才會立刻返回,否則該函式會阻塞在這裡 
    int shmid = shmget(key, SHMSIZE, 0666);
    if(shmid == -1){
        cerr << "shmget error ...." << endl;
        exit(-1);
    }

    pid_t pid = getpid();
    char * p = (char *)shmat(shmid, NULL, 0);
    cout << "process " << pid << " read: ";
    while(1){
        if(strlen(p) != 0)
            cout << p << endl;
        else
            continue;
        if(strcmp(p, "over") == 0){
            break;
        }
        cout << "process " << pid << " read: ";
        memset(p, 0, SHMSIZE);
    }
    cout << "程式退出。\n";
    exit(0);
}




相關文章