IPC: Shared Memory Example
我個人比較喜歡的 IPC 技術是 Unix Domain Socket,因為可以統一透過 File Descriptor 的處理機制來進行管理,如 epoll 或是 select 等。但即便是這樣,還是很多人會跟我說:「你有考慮過 Shared Memory 的方法嗎?效能應該會比較好唷。」我當然知道囉,不過隨著年紀增長,已經不再像以前一樣汲汲於效能上微小的差異(I mean ... 人的感受程度),而會把開發、維護的容易程度放在考量的第一位。所以我的第1選項目前都是:Unix Domain Socket,不但如此,之後也很容易直接改成網路的 socket 程式,何樂而不為。但因為以後可能還是有遇到必須使用 Shared Memory 的情況,所以還是寫篇文章來紀錄相關的資訊。
Shared Memory 的 IPC 方式,顧名思義,就是兩個 Process 直接存取同樣一塊的記憶體空間。一般來說,兩個獨立的 Process 都會有各自的 Virtual Memory 位址管理,彼此之間是無法互相存取到的。而使用了 Shared Memory 的機制,系統核心就會準備一塊記憶體位置並讓兩個 Process 都能互相存取。用下圖可以表示 Shared Memory 和 Unix Domain Socket 的不同:
上圖左邊雖然是寫 Unix Domain Socket,但其實用 lo 來做 UDP socket communication 也是同一類。我個人認為上圖很明顯的說明了兩種方式的效率差異。在網路上看到一篇很不錯的效能比較文章,連結如下:
Tcp Socket vs. Unix Domain Socket vs. Pipes vs. Shared Memory
這個網頁只有一個小缺點,他不應該用 TCP Socket 來比較而應該採用 UDP Socket,理由是 TCP 的 Overhead 大於 UDP,而本機端的溝通應該用不到那些機制。考量到外部網頁連結不一定會持續存在,因此我將相關的圖節錄如下:
接下來就是撰寫範例程式了。在這裡會撰寫兩隻程式,一支負責傳送資料,另外一支負責接受資料。範例的參考連結在下面:
http://www.cs.cf.ac.uk/Dave/C/node27.html
shm_server
shm_client
要注意的是上面的範例其實並沒有很好的處理 lock 的問題。以後有心情的話再來改良這支範例吧。
Shared Memory 的 IPC 方式,顧名思義,就是兩個 Process 直接存取同樣一塊的記憶體空間。一般來說,兩個獨立的 Process 都會有各自的 Virtual Memory 位址管理,彼此之間是無法互相存取到的。而使用了 Shared Memory 的機制,系統核心就會準備一塊記憶體位置並讓兩個 Process 都能互相存取。用下圖可以表示 Shared Memory 和 Unix Domain Socket 的不同:
上圖左邊雖然是寫 Unix Domain Socket,但其實用 lo 來做 UDP socket communication 也是同一類。我個人認為上圖很明顯的說明了兩種方式的效率差異。在網路上看到一篇很不錯的效能比較文章,連結如下:
Tcp Socket vs. Unix Domain Socket vs. Pipes vs. Shared Memory
這個網頁只有一個小缺點,他不應該用 TCP Socket 來比較而應該採用 UDP Socket,理由是 TCP 的 Overhead 大於 UDP,而本機端的溝通應該用不到那些機制。考量到外部網頁連結不一定會持續存在,因此我將相關的圖節錄如下:
接下來就是撰寫範例程式了。在這裡會撰寫兩隻程式,一支負責傳送資料,另外一支負責接受資料。範例的參考連結在下面:
http://www.cs.cf.ac.uk/Dave/C/node27.html
shm_server
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SHMSZ 17
int main()
{
int shmid = 0, i = 0;
key_t key;
char *shm = NULL;
// Segment key.
key = 8888;
// Create the segment.
if( ( shmid = shmget( key, SHMSZ, IPC_CREAT | 0666 ) ) < 0 )
{
perror( "shmget" );
exit(1);
}
// Attach the segment to the data space.
if( ( shm = shmat( shmid, NULL, 0 ) ) == (char *)-1 )
{
perror( "shmat" );
exit(1);
}
// Initialization.
memset( shm, 0, SHMSZ );
// Wait other processes to change the memory content.
// *shm == 0, nothing.
// *shm == 1, something changed.
// *shm == 2, bye.
while( *shm != 2 )
{
if( *shm == 1 )
{
for( i = 1 ; i < 17 ; i++ )
{
printf( "%02x ", *( shm + i ) );
}
printf( "\n" );
memset( shm, 0, SHMSZ );
}
sleep(1);
}
return 0;
}
shm_client
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SHMSZ 17
int main()
{
int shmid = 0, i = 0, running = 1;
key_t key;
char *shm = NULL;
char buffer[(SHMSZ - 1)];
// Segment key.
key = 8888;
// Create the segment.
if( ( shmid = shmget( key, SHMSZ, IPC_CREAT | 0666 ) ) < 0 )
{
perror( "shmget" );
exit(1);
}
// Attach the segment to the data space.
if( ( shm = shmat( shmid, NULL, 0 ) ) == (char *)-1 )
{
perror( "shmat" );
exit(1);
}
// Change the shared memory content.
// *shm == 0, wait for change.
// *shm == 1, not processed yet.
// *shm == 2, bye.
while( running )
{
if( *shm == 0 )
{
printf( "Please enter a msg (q for quit): " );
memset( buffer, 0, ( SHMSZ - 1 ) );
fgets( buffer, ( SHMSZ - 1 ), stdin );
if( buffer[0] == 'q' )
{
*shm = 2;
running = 0;
}
else
{
*shm = 1;
memcpy( shm + 1, buffer, ( SHMSZ - 1 ) );
}
}
sleep(1);
}
return 0;
}
要注意的是上面的範例其實並沒有很好的處理 lock 的問題。以後有心情的話再來改良這支範例吧。





留言
張貼留言