共享記憶體linux C/C++程式碼實戰------順便玩下ipcs, ipcrm, shmget, shmat, shmdt, shmctl
阿新 • • 發佈:2019-02-18
在學校的時候, 誰會搞共享記憶體這些東西呢? 不過是為了筆試和麵試, 大家才搞一下吧。 但是, 在實際工作中, 共享記憶體確實應用較廣。
其實, 共享記憶體的思想很簡單, 我來舉個俗氣的例子, writer程序和和reader程序通訊, 最簡單的方式是什麼: 當然是共享檔案啊。 writer程序把資料寫到a.txt檔案, 然後reader程序從a.txt檔案中讀取資料, 這就實現了程序間的通訊。 我當時讀書的時候, 就是這麼幹的。 在學校階段, 確實解決了當時的問題, 靠譜。 但在公司, 誰敢這麼搞?
共享記憶體也是採用了類似的思路, 只不過, 共享的不是檔案, 而是記憶體。 就是如此簡單。
話不多說, 來看點程式碼:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
int main()
{
int shmid = shmget((key_t)1234, 100, 0666|IPC_CREAT);
printf("shmid %d\n", shmid);
return 0;
}
key是1234, 對應的16進位制是0x000004d2, 100是設定的共享記憶體大小。 我們看看結果:
可以看到, 執行程式前, 沒有使用者xxxxxx對應的共享記憶體, 執行後, 建立了一塊共享記憶體, 其資訊和我們在程式中設定的資訊完全一致。xxxxxx:~/network> ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x115fd81a 32768 root 666 4096 2 0x294b8556 65537 root 666 13497727 1 ------ Semaphore Arrays -------- key semid owner perms nsems 0x0000870a 0 root 666 1 0x00008707 32769 root 666 1 0x00008709 65538 root 666 1 0x0000870b 98307 root 666 1 ------ Message Queues -------- key msqid owner perms used-bytes messages xxxxxx:~/network> xxxxxx:~/network> xxxxxx:~/network> xxxxxx:~/network> ./test shmid 294915 xxxxxx:~/network> ipcm -bash: ipcm: command not found xxxxxx:~/network> ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x115fd81a 32768 root 666 4096 2 0x294b8556 65537 root 666 13497727 1 0x000004d2 294915 xxxxxx 666 100 0 ------ Semaphore Arrays -------- key semid owner perms nsems 0x0000870a 0 root 666 1 0x00008707 32769 root 666 1 0x00008709 65538 root 666 1 0x0000870b 98307 root 666 1 ------ Message Queues -------- key msqid owner perms used-bytes messages xxxxxx:~/network>
這裡要注意一下幾點(有興趣的同學可以多多嘗試)
1. 呼叫shmget的時候, 如果共享記憶體key已經存在, 則不是建立一塊新共享記憶體, 而是返回已經存在的共享記憶體。
2. 程序退出後, 共享記憶體不會釋放, 需要呼叫shmctr函式, 或者用ipcrm命令才可釋放。
3. ipcs和ipcrm要用熟。
有點迫不及待看共享記憶體的實際程式碼了, 一起來看看:
writer.cpp
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#define TEST_SIZE 2048
typedef struct _BOX
{
int flag;
char szMsg[TEST_SIZE];
}Box;
int main()
{
int shmid = shmget((key_t)1234, sizeof(Box), 0666|IPC_CREAT);
void *shm = shmat(shmid, (void*)0, 0);
Box *pBox = (Box*)shm;
pBox->flag = 0;
int i = 0;
while(1)
{
while(pBox->flag == 0)
{
getchar();
snprintf(pBox->szMsg, sizeof(pBox->szMsg), "hello %d", ++i);
printf("write msg is [%s]\n", pBox->szMsg);
pBox->flag = 1;
}
}
shmdt(shm);
return 0;
}
reader.cpp的內容為:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#define TEST_SIZE 2048
typedef struct _BOX
{
int flag;
char szMsg[TEST_SIZE];
}Box;
int main()
{
int shmid = shmget((key_t)1234, sizeof(Box), 0666|IPC_CREAT);
void *shm = shmat(shmid, 0, 0);
Box *pBox = (Box*)shm;
while(1)
{
if(pBox->flag == 1)
{
printf("msg from writer is [%s]\n", pBox->szMsg);
pBox->flag = 0;
}
}
shmdt(shm);
shmctl(shmid, IPC_RMID, 0);
return 0;
}
先啟動writer, 再啟動reader, 於是乎, writer逐漸往共享記憶體中寫資料(按enter鍵), reader不斷讀共享記憶體的資料, 結果為(如下只給出reader端的結果):
msg from writer is [hello 1]
msg from writer is [hello 2]
msg from writer is [hello 3]
msg from writer is [hello 4]
msg from writer is [hello 5]
msg from writer is [hello 6]
msg from writer is [hello 7]
msg from writer is [hello 8]
msg from writer is [hello 9]
msg from writer is [hello 10]
可見, 在writer端不斷按enter鍵盤的時候, 訊息源源不斷地“流向”了reader, 就是如此簡單。 至於程式碼中的函式, 直接man一下, 一切就一目瞭然了。
共享記憶體是最快的程序間通訊方式, 沒有之一。 但同步的問題, 還得應用程式自己解決。
OK, 不多說。