Linux IPC進程間通信(二):共享內存

系列文章:
Linux IPC進程間通信(一):管道
Linux IPC進程間通信(二):共享內存
Linux IPC進程間通信(三):信號量
Linux IPC進程間通信(四):消息隊列


共享內存

  • key_t ftok(const char* filename, int proj_id)

通過已經存在的文件(filename) 與 proj_id(通常大於0) 創建出一個key值,用於進行共享內存的生成。

  • int shmget(key_t key, size_t size, int shmflag)

key代表着與共享內存相關的一個關鍵字,如果該關鍵字已經存在,那麼直接打開該共享內存,反之創建共享內存(一般使用 IPC_PRIVATE 用於創建新的共享內存)
size代表共享內存的大小
shmflag表示權限(一般爲0600), 如果時要進行創建的話則是 IPC_CREAT, 也可以加上 IPC_EXCL , 代表必須創建新的共享內存,已有則返回-1
成功返回shmid(共享內存段的id),失敗返回-1

  • void* shmat(int shmid, char* shmaddr, int shmflag)

操作類似mmap內存映射。
shmid代表已經存在的共享內存id
shmaddr代表是否需要自定義共享內存映射到特定位置(一般爲NULL,讓系統來選擇)
shmflag代表位標識(通常爲0)
成功返回共享內存段的首地址,失敗返回(void*)-1

  • int shmctl(int shmid, int cmd, shmid_ds* buf)

一般用來刪除共享內存段
shmid 代表共享內存段號
cmd 代表執行命令(一般爲 IPC_RMID)
buf 結構體的信息(一般爲NULL)

如果想要使用結構體的信息,也可以在cmd命令中輸入 IPC_STAT 來獲取結構體的信息,或是 IPC_SET 來設置結構體信息以改變共享內存

int test0()
{
    int ret;
    key_t key = ftok("file", 1);
    ERROR_CHECK(key, -1, "ftok")
    int shmid = shmget(key, 1024, 0600 | IPC_CREAT);
    ERROR_CHECK(shmid, -1, "shmget");
    char *buf = (char *)shmat(shmid, NULL, 0);
    ERROR_CHECK(buf, (char *)-1, "shmat");
    strcpy(buf, "hello");
    cout << "shared memory:" << buf << endl;
    struct shmid_ds shminfo;
    ret = shmctl(shmid, IPC_STAT, &shminfo);
    ERROR_CHECK(ret, -1 , "IPC_STAT");
    cout << shminfo.shm_perm.cgid << endl;
    shminfo.shm_perm.cgid = 666;
    shmctl(shmid, IPC_SET, &shminfo);
    cout << shminfo.shm_perm.cgid << endl;

    ret = shmctl(shmid, IPC_RMID, NULL);
    ERROR_CHECK(ret, -1, "shmctl");
    return 0;
}

另外,我們通常會使用 ipcs 命令來查看共享內存的使用:
在這裏插入圖片描述

案例一:親屬進程間通信

父進程寫入Hello, 子進程讀

int test1()
{
    int shmid = shmget(IPC_PRIVATE, 1024, 0600);
    ERROR_CHECK(shmid, -1, "shmget");
    char* buf = (char*)shmat(shmid, NULL, 0);
    ERROR_CHECK(buf, (char*)-1, "shmat");
    
    if (fork() > 0)
    {
        strncpy(buf, "hello", 5);
        wait(NULL);
        int ret = shmctl(shmid, IPC_RMID, NULL);
        ERROR_CHECK(ret, -1, "shmctl");
        exit(0);
    }
    else
    {
        sleep(1);//等待父進程寫完再讀
        cout << "reading from shared memory:" << buf << endl; 
        exit(0);
    }
    return 0;
}

輸出:
在這裏插入圖片描述


案例二:非親屬進程通信

寫端 寫入HelloWorld , 讀端進行讀取

reader.cpp:

int main()
{
    key_t key = ftok("file", 1);
    ERROR_CHECK(key, -1, "ftok");
    int shmid = shmget(key, 1024, 0600 | IPC_CREAT);
    ERROR_CHECK(shmid, -1, "shmget");
    char* buf = (char*)shmat(shmid, NULL, 0);
    ERROR_CHECK(buf, (char*)-1, "shmat");
    strncpy(buf, "Hello", 5);
    return 0;   
}

writer.cpp:

int main()
{
    key_t key = ftok("file", 1);
    ERROR_CHECK(key, -1, "ftok");
    int shmid = shmget(key, 1024, 0600);
    ERROR_CHECK(shmid, -1, "shmget");
    char* buf = (char*)shmat(shmid, NULL, 0);
    ERROR_CHECK(buf, (char*)-1, "shmat");
    cout << "reading from shared memory:" << buf << endl;
    int ret = shmctl(shmid, IPC_RMID, NULL);
    ERROR_CHECK(ret, -1, "shmctl");
    return 0;   
}

輸出:
在這裏插入圖片描述

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