1. 程式人生 > >共享記憶體linux C/C++程式碼實戰------順便玩下ipcs, ipcrm, shmget, shmat, shmdt, shmctl

共享記憶體linux C/C++程式碼實戰------順便玩下ipcs, ipcrm, shmget, shmat, shmdt, shmctl

       在學校的時候, 誰會搞共享記憶體這些東西呢? 不過是為了筆試和麵試, 大家才搞一下吧。 但是, 在實際工作中, 共享記憶體確實應用較廣。

       其實, 共享記憶體的思想很簡單, 我來舉個俗氣的例子, 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:~/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> 
       可以看到, 執行程式前, 沒有使用者xxxxxx對應的共享記憶體, 執行後, 建立了一塊共享記憶體, 其資訊和我們在程式中設定的資訊完全一致。

       這裡要注意一下幾點(有興趣的同學可以多多嘗試)

       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,  不多說。