靈修分享:亞略巴古的演講

亞略巴古的演說是使徒行傳一篇非常著名的講道。基督徒往往用這段經文來說明上帝的屬性,同時也會參考這段經文作為和外邦人互動的一個參考方式。最近因為團契查經查到這一段,重新思想後看到了以前沒有考慮過的面向,在這邊記錄一下。

徒17:16-34保羅在雅典等候他們的時候,看見滿城都是偶像,就心裏着急;於是在會堂裏與猶太人和虔敬的人,並每日在市上所遇見的人,辯論。還有伊壁鳩魯和斯多亞兩門的學士,與他爭論。有的說:「這胡言亂語的要說甚麼?」有的說:「他似乎是傳說外邦鬼神的。」這話是因保羅傳講耶穌與復活的道。他們就把他帶到亞略‧巴古,說:「你所講的這新道,我們也可以知道嗎?因為你有些奇怪的事傳到我們耳中,我們願意知道這些事是甚麼意思。」(雅典人和住在那裏的客人都不顧別的事,只將新聞說說聽聽。)
保羅站在亞略‧巴古當中,說:「眾位雅典人哪,我看你們凡事很敬畏鬼神。我遊行的時候,觀看你們所敬拜的,遇見一座壇,上面寫着『未識之神』。你們所不認識而敬拜的,我現在告訴你們。創造宇宙和其中萬物的神,既是天地的主,就不住人手所造的殿,也不用人手服事,好像缺少甚麼;自己倒將生命、氣息、萬物,賜給萬人。他從一本本:有古卷是血脈造出萬族的人,住在全地上,並且預先定準他們的年限和所住的疆界,要叫他們尋求神,或者可以揣摩而得,其實他離我們各人不遠;我們生活、動作、存留,都在乎他。就如你們作詩的,有人說:『我們也是他所生的。』我們既是神所生的,就不當以為神的神性像人用手藝、心思所雕刻的金、銀、石。世人蒙昧無知的時候,神並不監察,如今卻吩咐各處的人都要悔改。因為他已經定了日子,要藉着他所設立的人按公義審判天下,並且叫他從死裏復活,給萬人作可信的憑據。」
眾人聽見從死裏復活的話,就有譏誚他的;又有人說:「我們再聽你講這個吧!」於是保羅從他們當中出去了。 但有幾個人貼近他,信了主,其中有亞略‧巴古的官丟尼修,並一個婦人,名叫大馬哩,還有別人一同信從。

對基督徒來說,保羅這篇講道講的真好,不但講出了上帝的超越性(像是不住人手所造的殿、也不是金銀石的彫刻),也帶出了耶穌基督復活的大能。但最近我才注意到眾人的反應:「眾人聽見從死裏復活的話,就有譏誚他的;又有人說:「我們再聽你講這個吧!」」不曉得你看到這一段有什麼感想?可能我是玻璃心吧,如果我是保羅,我大概會非常非常的難過,看起來似乎沒有人理會這個福音、這篇講道。這篇被基督…

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

#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 的問題。以後有心情的話再來改良這支範例吧。






留言

這個網誌中的熱門文章

如何將Linux打造成OpenFlow Switch:Openvswitch

我弟家的新居感恩禮拜分享:善頌善禱

如何利用 Wireshark 來監聽 IEEE 802.11 的管理封包