Linux 線程與進程,以及通訊

http://blog.chinaunix.net/uid-25324849-id-3110075.htmlphp

 

部分轉自:http://blog.chinaunix.net/uid-20620288-id-3025213.htmlhtml

 

1、首先要明確進程和線程的含義:java

進程(Process)是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,是系統進行資源分配和調度的一個獨立單位。與程序相比,程序只是一組指令的有序集合,它自己沒有任何運行的含義,只是一個靜態實體。進程是程序在某個數據集上的執行,是一個動態實體。它因建立而產生,因調度而運行,因等待資源或事件而被處於等待狀態,因完成任務而被撤消,反映了一個程序在必定的數據集上運行的所有動態過程。linux

每一個正在系統上運行的程序都是一個進程。每一個進程包含一到多個線程。進程也多是整個程序或者是部分程序的動態執行。線程是一組指令的集合,或者是程序的特殊段,它能夠在程序裏獨立執行。也能夠把它理解爲代碼運行的上下文。因此線程基本上是輕量級的進程,它負責在單個程序裏執行多任務。一般由操做系統負責多個線程的調度和執行。算法

多線程是爲了同步完成多項任務,不是爲了提升運行效率,而是爲了提升資源使用效率來提升系統的效率。線程是在同一時間須要完成多項任務的時候實現的。編程

使用線程的好處有如下幾點:數組

a)使用線程能夠把佔據長時間的程序中的任務放到後臺去處理服務器

b)用戶界面能夠更加吸引人,這樣好比用戶點擊了一個按鈕去觸發某些事件的處理,能夠彈出一個進度條來顯示處理的進度網絡

c)程序的運行速度可能加快數據結構

d)在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。在這種狀況下咱們能夠釋放一些珍貴的資源如內存佔用等等。

2、其次來看下線程和進程的關係

線程是屬於進程的,線程運行在進程空間內,同一進程所產生的線程共享同一內存空間,當進程退出時該進程所產生的線程都會被強制退出並清除。線程可與屬於同一進程的其它線程共享進程所擁有的所有資源,可是其自己基本上不擁有系統資源,只擁有一點在運行中必不可少的信息(如程序計數器、一組寄存器和棧)。

3、而後咱們來看下線程和進程間的比較

 

子進程繼承父進程的屬性:

子線程繼承主線程的屬性:

實際用戶ID,實際組ID,有效用戶ID,有效組ID;

附加組ID;

進程組ID;

會話ID;

控制終端;

設置用戶ID標誌和設置組ID標誌;

當前工做目錄;

根目錄;

文件模式建立屏蔽字(umask);

信號屏蔽和安排;

針對任一打開文件描述符的在執行時關閉(close-on-exec)標誌;

環境;

鏈接的共享存儲段;

存儲映射;

資源限制;

進程中的全部信息對該進程的全部線程都是共享的;

可執行的程序文本;

程序的全局內存;

堆內存;

棧;

文件描述符;

信號的處理是進程中全部線程共享的(注意:若是信號的默認處理是終止該進程那麼便是把信號傳給某個線程也同樣會將進程殺掉)

 

父子進程之間的區別:

子線程特有的:

fork的返回值(=0子進程);

進程ID不一樣;

兩個進程具備不一樣的父進程ID;

子進程的tms_utime,tms_stime,tms_cutime以及tms_ustime均被設置爲0;

不繼承父進程設置的文件鎖;

子進程的未處理鬧鐘被清除;

子進程的未處理信號集設置爲空集;

線程ID;

一組寄存器值;

棧;

調度優先級和策略;

信號屏蔽字;

errno變量;

線程私有數據;

 

 

 

3、設計時考慮的使用技巧

1.儘可能避免長駐內存的進程,例如那些不多用到的功能,或週期性很長(10分鐘以上),把它們的功能提取出來,作成一個小的應用程序。須要的時候再把它們拉起來(如經過crontab配置,或直接system)。

2.把目標設計成子功能系統的組合可用提升重用的易用性和維護性。 
把目標根據功能劃分不一樣的子系統,子系統間遵循特定的協議(文本或XML),由通信聯繫起來,協做完成目標。

也就是說,咱們在作設計的時候能夠以下考慮:

一、線程的建立以及線程間的通訊和同步都比進程要快。在多核CPU上的任務分割是對線程而言的,不是進程。

二、若是不須要頻繁的建立和銷燬 執行的效率是並很少的,須要頻繁建立的話,線程快。

三、其它的就根據你的實際狀況選擇了, 要是沒有數據通訊什麼的,線程間的通訊比進程間方便。最關鍵的一點,多線程可讓同一個程序的不一樣部分併發執行。

因此在作安防系統的時候,報警系統和監控系統之間能夠用多進程來作,對於報警系統中能夠用多線程來實現若是發生意外,能夠向用戶發送消息,同時鳴笛,以及若是是火警的話,能夠打開閥門等。

 

 

進程間通訊

  unix系統主要進程間通訊機制(IPC

 

管道

FIFO(命名管道)

消息隊列

共享內存

信號量

套接字

3.  管道

詳細請見:

http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207407

 

管道是最多見的IPC機制,是單工的,若是要兩個進程實現雙向傳輸則須要兩個管道,管道建立的時候既有兩端,一個讀端和一個寫端。兩個進程要協調好,一個進程從讀的方向讀,一個進程從寫的方向寫,而且只能在關係進程間進行,好比父子進程,經過系統調用pipe()函數實現。

 

#include

int pipe(int fd[2]);

fd[0]:文件描述符,用於讀操做

fd[1]:文件描述符,用於寫操做

返回值:成功返回0,若是建立失敗將返回-1並記錄錯誤碼

4.  FIFO

詳細請見:

http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207413

 

FIFO又稱命名管道,經過FIFO的通訊能夠發生在任何兩個進程之間,且只須要對FIFO有適當的訪問權限,對FIFO的讀寫操做與普通文件相似,命名管道的建立是經過mkfifo()函數建立的。

    #include

    int mkfifo(const char *filename, mode_t mode)

    filename:命名管道的文件名

    mode:訪問權限

返回值:若成功則返回0,不然返回-1,錯誤緣由存於errno中。

4.1 FIFO服務器實例

 

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

 

    #define SERVER_FIFO_NAME "./serv_fifo"

    #define CLIENT_FIFO_NAME "./cli_%d_fifo"

 

    #define BUFFER_SIZE 20

 

    struct data_to_pass_st {

       pid_t  client_pid;

       char   some_data[BUFFER_SIZE - 1];

       };

 

    int main()

    {

    int server_fifo_fd, client_fifo_fd;

    struct data_to_pass_st my_data;

    int read_res;

    char client_fifo[256];

    char *tmp_char_ptr;

 

    mkfifo(SERVER_FIFO_NAME, 0777);

    server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);

    if (server_fifo_fd == -1) {

       fprintf(stderr, "Server fifo failure\n");

       exit(EXIT_FAILURE);

       }

 

    sleep(10); /* lets clients queue for demo purposes */

 

    do {

       read_res = read(server_fifo_fd, &my_data, sizeof(my_data));

       if (read_res > 0) {

          tmp_char_ptr = my_data.some_data;

          while (*tmp_char_ptr) {

         *tmp_char_ptr = toupper(*tmp_char_ptr);

             tmp_char_ptr++;

             }

          sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid);

          client_fifo_fd = open(client_fifo, O_WRONLY);

          if (client_fifo_fd != -1) {

             write(client_fifo_fd, &my_data, sizeof(my_data));

             close(client_fifo_fd);

             }

          }

       } while (read_res > 0);

    close(server_fifo_fd);

    unlink(SERVER_FIFO_NAME);

    exit(EXIT_SUCCESS);

    }

4.2 FIFO客戶實例

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

 

    #define SERVER_FIFO_NAME "./serv_fifo"

    #define CLIENT_FIFO_NAME "./cli_%d_fifo"

 

    #define BUFFER_SIZE 20

 

    struct data_to_pass_st {

       pid_t  client_pid;

       char   some_data[BUFFER_SIZE - 1];

       };

 

    int main()

    {

    int server_fifo_fd, client_fifo_fd;

    struct data_to_pass_st my_data;

    int times_to_send;

    char client_fifo[256];

 

    server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY);

    if (server_fifo_fd == -1) {

       fprintf(stderr, "Sorry, no server\n");

       exit(EXIT_FAILURE);

       }

 

    my_data.client_pid = getpid();

    sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid);

    if (mkfifo(client_fifo, 0777) == -1) {

       fprintf(stderr, "Sorry, can't make %s\n", client_fifo);

       exit(EXIT_FAILURE);

       }

 

    for (times_to_send = 0; times_to_send < 5; times_to_send++) {

       sprintf(my_data.some_data, "Hello from %d", my_data.client_pid);

       printf("%d sent %s, ", my_data.client_pid, my_data.some_data);

       write(server_fifo_fd, &my_data, sizeof(my_data));

       client_fifo_fd = open(client_fifo, O_RDONLY);

       if (client_fifo_fd != -1) {

          if (read(client_fifo_fd, &my_data, sizeof(my_data)) > 0) {

             printf("received: %s\n", my_data.some_data);

             }

          close(client_fifo_fd);

          }

       }

    close(server_fifo_fd);

    unlink(client_fifo);

    exit(EXIT_SUCCESS);

    }

 

5.  消息隊列

詳細請見:

http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207459

 

消息隊列有以下特色:

(1)    經過消息隊列key值來定義和生成消息隊列

(2)    任何進程只要有訪問權限而且知道key就能夠訪問消息隊列

(3)    消息隊列爲內存塊方式數據段

(4)    消息隊列的消息長度可爲系統參數限制內的任何長度

(5)    消息隊列有消息類型,訪問能夠按類型訪問

(6)    在一次讀寫操做前都必須取得消息標識符,即訪問權,訪問後脫離關係

(7)    消息隊列中的某條消息被讀後當即自動的從消息隊列中刪除

(8)    消息隊列具備加鎖處理機制

(9)    在權限容許時,消息隊列的信息能夠雙向傳遞

6.  共享內存

詳細請見:

http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207467

 

共享內存是效率最高的IPC機制,他容許任何兩個進程訪問相同的邏輯內存區,它具備一下特色:

(1)    經過共享內存key值定義和生成共享內存

(2)    任何進程只要有訪問權限而且知道key就能夠訪問共享內存

(3)    共享內存爲內存塊方式數據段

(4)    共享內存的消息長度可爲系統參數限制內的任何長度

(5)    共享內存的訪問方式與數組的訪問方式相同

(6)    在取得共享內存標識符將共享內存與進程數據段鏈接後便可以開始對其進行讀寫操做,在全部操做完成以後再作共享內存與進程數據段的脫離操做,才完成內存訪問的過程

(7)    共享內存中的數據不會由於數據被進程讀取後消失

(8)    共享內存不具有鎖機制,全部共享內存最好與信號量一塊兒使用來保證數據的一致性

(9)    在權限容許時,共享內存的信息傳遞時雙向的

 

7.  信號量

詳細請見:

http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207464

 

信號量是一種同步機制,主要用途是保護臨界資源(在一個時刻只能被一個進程所擁有),一般與共享內存一塊兒使用。

 

6.1 semget()函數

#include

int semget(key_t key, int num_sems, int sem_flags)

 

key:信號量集合的鍵

num_sems:信號量集合裏面元素個數

sem_flags:任選參數

返回值:返回信號量集合標識符,出錯返回-1

 

6.2 semop()函數

#include

int semop(int sem_id, struct sembuf *sem_ops , size_t num_sem_ops)

 

sem_id: 信號量集合標識符

sem_ops:信號量操做結構的指針

num_sem_ops:信號量操做結構的個數

 

6.3 semctl)函數

#include

int semctl (int sem_id, int sem_num, int command, …)

 

sem_id: 信號量集合標識符

sem_num:信號量元素編號

command:控制命令

…:命令參數列表

返回值:根據命令返回相應的值,出錯返回-1

 

http://timyang.net/linux/linux-process/

上週碰到部署在真實服務器上某個應用CPU佔用太高的問題,雖然通過tuning, 問題貌似已經解決,但我對tuning的方式只是基於大膽的假設並最終生效了。我更但願更多的求證一下程序背後CPU及OS kernel當時的運做機制。因此我讀了一些Linux內核設計與實現及其餘一些相關資料,對Linux process的機制與切換有了更多一些體會。本文儘量條理一點,但因爲牽涉點較多,同時本身可能以爲某些點有記錄的價值,所以文字可能會零散。

  • 進程狀態

Linux進程的狀態比較容易理解,值得注意的是 UNINTERRUPTIBLE 及 ZOMBIE

TASK_RUNNING
TASK_INTERRUPTIBLE
TASK_UNINTERRUPTIBLE 此時進程不接收信號,這就是爲何有時候kill一個繁忙的進程沒有響應。
TASK_ZOMBIE 咱們常常 kill -9 pid 以後運行ps會發現被kill的進程仍然存在,狀態爲 zombie。zombie的進程實際上已經結束,佔用的資源也已經釋放,僅因爲kernel的相關進程描述符還未釋放。
TASK_STOPPED

  • Kernel space and user space

Kernel space是供內核,設備驅動運行的內存區域。user space是供普通應用程序運行的區域。每個進程都運行在本身的虛擬內存區域,不能訪問其餘進程的內存空間。普通進程不能訪問kernel space, 只能經過系統調用來間接進行。當系統內存比較緊張時,非當前運行進程user space可能會被swap到磁盤。

使用命令 pmap -x 能夠查看進程的內存佔用信息; lsof -a -p 能夠查看一個進程打開的文件信息。ps -Lf 能夠查看進程的線程數。

另外procfs也是一個分析進程結構的好地方。procfs是一個虛擬的文件系統,它把系統中正在運行的進程都顯如今/proc/目錄下。

  • 進程建立

進程建立一般調用fork實現。建立後子進程和父進程指向同一內存區域,僅當子進程有write發生時候,纔會把改動的區域copy到子進程新的地址空間,這就是copy-on-write技術,它極大的提升了建立進程的速度。

  • Linux的線程實現

Linux線程是經過進程來實現。Linux kernel爲進程建立提供一個clone()系統調用,clone的參數包括如 CLONE_VM, CLONE_FILES, CLONE_SIGHAND 等。經過clone()的參數,新建立的進程,也稱爲LWP(Lightweight process)與父進程共享內存空間,文件句柄,信號處理等,從而達到建立線程相同的目的。

Linux 2.6的線程庫叫NPTL(Native POSIX Thread Library)。POSIX thread(pthread)是一個編程規範,經過此規範開發的多線程程序具備良好的跨平臺特性。儘管是基於進程的實現,但新版的NPTL建立線程的效率很是高。一些測試顯示,基於NPTL的內核建立10萬個線程只須要2秒,而沒有NPTL支持的內核則須要長達15分鐘。

在Linux 2.6以前,Linux kernel並無真正的thread支持,一些thread library都是在clone()基礎上的一些基於user space的封裝,所以一般在信號處理、進程調度(每一個進程須要一個額外的調度線程)及多線程之間同步共享資源等方面存在必定問題。爲了解決這些問題,當年IBM曾經開發一套NGPT(Next Generation POSIX Threads), 效率比 LinuxThreads有明顯改進,但因爲NPTL的推出,NGPT也完成了相關的歷史使命並中止了開發。

NPTL的實現是在kernel增長了futex(fast userspace mutex)支持用於處理線程之間的sleep與wake。futex是一種高效的對共享資源互斥訪問的算法。kernel在裏面起仲裁做用,但一般都由進程自行完成。

NPTL是一個1×1的線程模型,即一個線程對於一個操做系統的調度進程,優勢是很是簡單。而其餘一些操做系統好比Solaris則是MxN的,M對應建立的線程數,N對應操做系統能夠運行的實體。(N<m),優勢是線程切換快,但實現稍複雜。< p="">

  • 信號

進程接收信號有兩種:同步和異步。同步信號好比SEGILL(非法訪問), SIGSEGV(segmentation fault)等。發生此類信號以後,系統會當即轉到內核陷阱處理程序,所以同步信號也稱爲陷阱。異步信號如kill, lwp_kill, sigsend等調用產生的都是,異步信號也稱爲中斷。

kill 調用的是 SIGTERM, 此信號能夠被捕獲和忽略。

kill -9 調用的是 SIGKILL, 殺掉進程,不能被捕獲和忽略。

SIGHUP是在終端被斷開時候調用,若是信號沒有被處理,進程會終止。這就是爲何忽然斷網剛經過遠程終端啓動的進程都終止的緣由。防止的方法是在啓動的命令前加上 nohup 命令來忽略 SIGHUP信號。如 nohup ./startup.sh &

不少應用程序一般捕獲SIGHUP用來實現一些自定義特性,好比經過控制檯傳遞信號讓正在運行的程序從新加載配置文件,避免重啓帶來的中止服務的反作用。惋惜的是,在JAVA中無法直接使用這一功能,SUN JVM沒有官方的signal支持,儘管它已經能夠實現,詳情可參看Singals and Java.

另外有個有趣的現象是 zombie 狀態的進程 kill/kill -9 都沒有任何做用,這是因爲進程自己已經不存在,因此沒有相應的進程來處理signal, zombie狀態的進程只是kernel中的進程描述符及相關數據結構沒有釋放,但進程實體已經不存在了。

關於殭屍進程,也可參看下酷殼上的這篇Linux 的殭屍(zombie)進程,從程序的角度解釋了相關原理。

 
 
幾種進程通訊方法的研究和比較
陸靜.胡明慶 (寧波大學科學技術學院理工分院浙江寧波315211) 1.引言 爲了提升計算機系統的效率.加強計算機系統內各類硬件 的並行操做能力.操做系統要求程序結構必須適應併發處理的 須要.爲此引入了進程的概念。進程是操做系統的核心,全部基 於多道程序設計的操做系統都創建在進程的概念之上。目前的 計算機系統均提供了多任務並行環境.不管是應用程序仍是系 統程序.都須要針對每個任務建立相應的進程。進程是設計和 分析操做系統的有力工具。然而不一樣的進程之間.即便是具備家 族聯繫的父子進程.都具備各自不一樣的進程映像。因爲不一樣的進 程運行在各自不一樣的內存空間中.一方對於變量的修改另外一方 是沒法感知的.所以.進程之間的信息傳遞不可能經過變量或其 它數據結構直接進行,只能經過進程間通訊來完成。併發進程之 間的相互通訊是實現多進程間協做和同步的經常使用工具.具備很 強的實用性 2.進程通訊分類 進程通訊是操做系統內核層極爲重要的部分 根據進程通 信時信息量大小的不一樣,能夠將進程通訊劃分爲兩大類型:控制 信息的通訊和大批數據信息的通訊.前者稱爲低級通訊,後者稱 爲高級通訊 低級通訊主要用於進程之間的同步、互斥、終止、掛起等等 控制信息的傳遞,主要有如下三種方式: (1)利用系統調用睡眠SLEEP()和喚醒WAKEUP()實現 進程之間的同步,互斥。SLE EP可使調用它的進程以指定的優 先級在系統的某個等待隊列上睡眠.而WAKEUP則用來喚醒在 指定隊列上睡眠的進程 (2)利用系統調用WAIT'()和EXIT()實現父子進程之間的 同步 調用WAIT的父進程必須等待子進程運行結束才能繼續 運行,而EXIT則能夠用來終止某一個進程,並把相關狀態返回 給它的父進程 (3)利用軟中斷信號實現同一用戶的各進程之間的通訊。 高級通訊主要用於進程間數據塊的交換和共享 常見的高級通 信有管道(PIPE)、消息隊列(MESSAGE)、共享內存(SHARED MEM0RY)等。 3.軟中斷通訊 軟中斷信號是一種簡單且最基本的進程間通訊機制.它最 大的特色是提供了一種簡單的處理異步事件的方法。例如,咱們 常見的用戶從鍵盤輸入組合鍵Ctrl+C來中斷一個程序的運行. 或者在兩個進程之間經過某個信號來通知發生了異步事件.或 者向系統或進程報告突發的硬件故障如非法指令、運算溢出等 等 更重要的是用戶進程還能夠向本身發送信號以中斷程序的 執行.並自動轉入指定的軟中斷處理函數中去執行用戶自行安 排的處理內容.處理完畢後再返回用戶進程繼續執行.從而爲應 用程序提供了由用戶自行處理隨機事件的通訊機制。 所以,軟中斷信號實現(signal implementation)是操做系統 用來通知進程有事件發生的一種機制 因爲這種信號老是在進 程處於運行狀態時纔會去響應的.故稱之爲軟中斷信號。 軟中斷信號的使用者是操做系統和用戶源程序.操做系統 事先將系統中可使用的軟中斷信號進行集中編碼並定義相應 含義後.提交用戶使用。用戶能夠經過相應的軟中斷序號或軟中 斷名稱來使用軟中斷 4.管道通訊(PIPE) 管道是一種經常使用的單向進程間通訊機制 兩個進程利用管 道進行通訊時.發送信息的進程稱爲寫進程.接收信息的進程稱 爲讀進程。管道通訊方式的中間介質就是文件.一般稱這種文件 爲管道文件.它就像管道同樣將一個寫進程和一個讀進程鏈接 在一塊兒,實現兩個進程之間的通訊。寫進程經過寫入端(發送端) 往管道文件中寫入信息;讀進程經過讀出端(接收端)從管道文 件中讀取信息。兩個進程協調不斷地進行寫和讀,便會構成雙方 經過管道傳遞信息的流水線。 利用系統調用PIPE()能夠建立一個無名管道文件,一般稱 爲無名管道或PIPE;利用系統調用MKNOD()能夠建立一個有 名管道文件.一般稱爲有名管道或FIFO。無名管道是一種非永 久性的管道通訊機構.當它訪問的進程所有終止時,它也將隨之 被撤消。無名管道只能用在具備家族聯繫的進程之間。有名管道 能夠長期存在於系統之中.並且提供給任意關係的進程使用,但 是使用不當容易致使出錯.因此操做系統將命名管道的管理權 交由系統來加以控制 管道文件被建立後,能夠經過系統調用WRITE()和READ ()來實現對管道的讀寫操做;通訊完畢後,可用CLOSE()將管道 文件關閉。 5.消息緩衝通訊(MESSAGE) 多個獨立的進程之間能夠經過消息緩衝機制來相互通訊. 這種通訊的實現是以消息緩衝區爲中間介質.通訊雙方的發送 和接收操做均以消息爲單位。在存儲器中,消息緩衝區被組織成 隊列,一般稱之爲消息隊列。消息隊列一旦建立後便可由多進程 共享.發送消息的進程能夠在任意時刻發送任意個消息到指定 的消息隊列上,並檢查是否有接收進程在等待它所發送的消息。 如有則喚醒它:而接收消息的進程能夠在須要消息的時候到指 定的消息隊列上獲取消息.若是消息尚未到來.則轉入睡眠狀 態等待。 因爲一個消息隊列由多個進程共享.所以掛在隊列上的消 息須要統一規格。以Linux爲例.系統定義了一個公用的消息緩 衝區數據結構msgbuf.而消息隊列則是由若干msgbuf構成的鏈 表。利用系統調用MSGGET()能夠建立消息隊列,這一步工做也 被稱爲消息隊列的初始化。在進行消息緩衝通訊時.發送消息進 程使用系統調用MSGSND()將消息掛人消息隊列,接收消息進 程使用系統調用MSGREC()從消息隊列上摘取消息。在須要改 變隊列的使用權限及其它一些特性時,用MSGCTL()來實現。 共享的消息隊列是一個臨界資源,針對同一消息隊列的諸 發送和接收進程必須保證互斥進入,這種進程間的同步和互斥 是由系統提供的系統調用自動實現的,因此用戶在使用時不需 要再考慮它們之間的同步關係.很是方便。 可是消息發送進程在發送消息前必須先請求一個msgbuf, 而後將要發送的消息從私有的地址空間中複製 到msgbuf中才能發送;消息接收進程則相反,必須先從消息隊 列上摘取消息msgbuf.再將msgbuf中的信息複製到本身的程序 空間中。所以,在消息緩衝通訊方式中須要進行大量額外的複製 操做,這是消息緩衝通訊方式的缺點。 6.共享內存通訊(SHARED MEMORY) 針對消息緩衝須要佔用CPU進行消息複製的缺點.OS提 供了一種進程間直接進行數據交換的通訊方式一共享內存 顧 名思義.這種通訊方式容許多個進程在外部通訊協議或同步,互 斥機制的支持下使用同一個內存段(做爲中間介質)進行通訊. 它是一種最有效的數據通訊方式,其特色是沒有中間環節.直接 將共享的內存頁面經過附接.映射到相互通訊的進程各自的虛 擬地址空間中.從而使多個進程能夠直接訪問同一個物理內存 頁面.如同訪問本身的私有空間同樣(但實質上不是私有的而是 共享的)。所以這種進程間通訊方式是在同一個計算機系統中的 諸進程間實現通訊的最快捷的方法.而它的侷限性也在於此.即 共享內存的諸進程必須共處同一個計算機系統.有物理內存可 以共享才行。 與消息緩衝通訊相似.在進行共享內存通訊以前.必須先通 過系統調用SHMGET()建立一個共享內存段.而後使用系統調 用SHMAT()和SHMDT()來實現共享內存的映射和分離.用系 統調用SHMCTL()來改變共享內存段的存取權限及其它一些特 性。 共享內存通訊與消息緩衝通訊有不少類似之處:多個進程 都是經過獲取共享內存的標識符來訪問指定的共享內存.都要 進行權限檢查等等。不一樣的是共享內存一旦附接後就做爲進程 地址空間的一部分提供給進程使用 對於該共享內存的讀寫操 做如同對進程私有的緩衝區同樣.操做系統再也不關心進程間是 如何使用這個共享內存,更沒法進行干預。所以。系統提供的共 享內存系統調用函數是不帶同步工具的. 多個進程對共享內存 的讀寫操做所須要的同步和互斥則必須由各進程經過使用其它 的同步工具來解決。 7.幾種通訊方法總結 綜上所述.進程之間的多種通訊方法各自有各自的優勢和 缺點: 若是用戶傳遞的信息較少.或是須要經過信號來觸發某些 行爲.前文提到的軟中斷信號機制不失爲一種簡捷有效的進程 間通訊方式.但如果進程間要求傳遞的信息量比較大或者進程 間存在交換數據的要求,那就須要考慮別的通訊方式了。 無名管道簡單方便.但侷限於單向通訊的工做方式.而且只 能在建立它的進程及其子孫進程之間實現管道的共享:有名管 道雖然能夠提供給任意關係的進程使用.可是因爲其長期存在 於系統之中,使用不當容易出錯.因此普通用戶通常不建議使 用。 消息緩衝能夠再也不侷限於父子進程.而容許任意進程經過 共享消息隊列來實現進程間通訊.並由系統調用函數來實現消 息發送和接收之間的同步.從而使得用戶在使用消息緩衝進行 通訊時再也不須要考慮同步問題.使用方便,可是信息的複製須要 額外消耗CPU的時間.不適宜於信息量大或操做頻繁的場合。 共享內存針對消息緩衝的缺點改而利用內存緩衝區直接交 換信息,無須複製,快捷、信息量大是其優勢。可是共享內存的通 信方式是經過將共享的內存緩衝區直接附加到進程的虛擬地址 空間中來實現的.所以,這些進程之間的讀寫操做的同步問題操 做系統沒法實現。必須由各進程利用其餘同步工具解決。另外, 因爲內存實體存在於計算機系統中.因此只能由處於同一個計 算機系統中的諸進程共享。不方便網絡通訊。 不一樣的進程通訊方式有不一樣的優勢和缺點.所以.對於不一樣 的應用問題,要根據問題自己的狀況來選擇進程間的通訊方式。 參考文獻: 1.胡明慶、高魏、鍾梅.操做系統與實驗教程.清華大學出版社.2006年 8月 2.龐麗萍。操做系統原理.牟中科技大學出版社。2ooo卑 3.黃超.1mux高級開發技術.機械工業出版社.2002年
相關文章
相關標籤/搜索