1. 程式人生 > >程式設計師面試寶典隨筆記(一)---執行緒和程序1,-基礎資訊

程式設計師面試寶典隨筆記(一)---執行緒和程序1,-基礎資訊

①程式,程序,執行緒的區別


程式:程式是由一系列的指令和邏輯組成的一個靜態檔案(如cpp檔案),無論能不能執行,它都客觀的存在於儲存器中。


程序:程序是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位--來源於百度百科。如果你是初學者,可能你並不能真正地理解這句話。通俗地說,系統為特定的靜態程式分配好執行時需要的各種資源,這個時候系統會連帶地生成一個PCB(程序控制塊,一種資料結構)用來記錄程式執行時(這裡的執行並不是指程序的執行態)的各種資訊(如程序當前的狀態等),這個時候你的程式就可以運行了,只需要等待CPU對其的呼叫,我們用程序來稱呼其為程式的一次執行。


執行緒:在以前,程序是系統獨立排程和分派的基本單位,後面由於多道處理的出現,產生了併發的概念(不明白併發的話可以先看第②點),它加大了系統的容量與對硬體的利用率。我們知道,對於單處理器的機器來說,實現併發典型的方法便是使用分時,即CPU將時間片按特定演算法分發給各個程序,雖然總的計算次數可能並沒有發生什麼變化,但是由於CPU的計算速度越來越快,從巨集觀上來看,幾個程序就像是在同一時間段內執行的。於是,當程序A的時間用完了之後就要切換到另一個程序B,此時計算機需要為程序A儲存下結束時的狀態以便下一次從上一次結束處繼續執行,還需要為程序B的執行做各種準備工作,由於程序相對而言比較大,反覆切換會浪費很多的資源,所以人們想能不能將系統獨立排程和分派的基本單位做得更小,以減少程序切換所浪費的資源--於是執行緒出現了。現在,大部分的OS都是以執行緒為系統獨立排程和分派的基本單位

。另外,程序是由一個或者多個執行緒組成,執行緒是程序中的一個實體,是被系統獨立排程和分派的基本單位,執行緒自己不擁有系統資源,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個程序的其它執行緒共享程序所擁有的全部資源。一個執行緒可以建立和撤消另一個執行緒,同一程序中的多個執行緒之間可以併發執行。


給大家舉一個例子:

假如你是一個很牛逼的科學家,至少是愛因斯坦那種,呵呵,某一天你突然產生了一個念頭--你要做一個機器人女朋友,她無所不能,大家可以盡情想象!一天之內你就將整個生產流程以及各種製造細節都記錄在了紙上程式)。儘管你很牛逼,但是你卻很孤傲,從不發表自己的發明,結果肯定就是你比較窮,於是你缺少各種原料

來實現(資源)。上帝總是很眷顧你!於是第二天你就莫名其妙有了各種原料,開始著手於組建你的無所不能的機器人女友(程序)。當然製作的過程肯定是分得很細的,如製造頭,製造手等等(執行緒),你每花1分鐘的時間來製造頭就會花1分鐘的時間來製造手(併發)。最後,你的女朋友做好了,盡情地享受吧!


②併發,並行的區別


併發:同一時間段內交替執行多個程序(執行緒) 並行:同一時刻執行多個程序(執行緒)。很明顯,只有多處理器才能支援。
併發就像我們的大腦思考一樣,同一個時刻只能想一件事,但是在很短的一個時間段內我們可以三心二意。當然如果你長了幾個腦袋,那你就可以並行思考了呵呵。


③同步與非同步,阻塞與非阻塞方式


讓我們再來了解一下同步非同步阻塞非阻塞這個概念,加深對多執行緒程式設計的理解。
有了之前的概念,我們可以想象,當幾個執行緒或者程序在併發執行時,如果我們不加任何干預措施,那麼他們的執行順序是由系統當時的環境來決定的,所以不同時間段不同環境下執行的順序都會不盡相同,這便是非同步(有差異的步驟)。當然,同步肯定就是通過一定的措施,使得幾個執行緒或者程序總是按照一定順序來執行(總是按照相同的步驟)
當一個程序或者執行緒請求某一個資源而不得時,如I/O,便會進入阻塞狀態,一直等待。scanf()便是一個很好的例子,當程式執行到scanf()時,如果輸入快取區為空,那麼程式便會進入阻塞狀態等待我們從鍵盤輸入,這便是以阻塞的方式呼叫scanf()。 通過一定方法,我們可以將scanf()變成非阻塞的方式來執行。如給scanf()設定一個超時時間,如果時間到了還是沒有輸入那麼便跳過scanf(),這個時候我們就稱為用非阻塞的方式來呼叫scanf()。
對比可以發現,同步即阻塞。想要按照某特定順序來執行一系列過程,在上一個過程完成之前下一個過程必須等待,這就是阻塞在了這個地方。當同步執行的時候,會等待同步操作完成才會返回,否則會一直阻塞在同步操作處。
相反的,非同步即非阻塞,當非同步呼叫某個函式時,函式會立刻返回,而不會阻塞在那。 怎麼判斷非同步操作是否已經完成?通常有3種方式: 1.狀態:非同步操作完成時會將某個全域性變數置為特定值,可以通過輪詢判斷變數的值以確定是否操作完成。 2.通知:非同步操作完成會給呼叫者傳送特定訊號。 3.回撥:非同步操作完成時會呼叫回撥函式。
所以同步即阻塞,非同步即非阻塞。

執行緒程序的通訊和同步:

摘要

本文主要是為了總結作業系統裡面的程序與執行緒通訊。 作業系統的主要任務是管理計算機的軟體、硬體資源。現代作業系統的主要特點是多使用者和多工,也就是程式的並行執行,windows如此linux也是如此。所以作業系統就藉助於程序來管理計算機的軟、硬體資源,支援多工的並行執行。要並行執行就需要多程序、多執行緒。因此多程序和多執行緒間為了完成一定的任務,就需要進行一定的通訊。而執行緒間通訊又和程序間的通訊不同。由於程序的資料空間相對獨立而執行緒是共享資料空間的,彼此通訊機制也很不同。

一、程序間通訊

程序間的通訊,它的資料空間的獨立性決定了它的通訊相對比較複雜,需要通過作業系統。以前程序間的通訊只能是單機版的,現在作業系統都繼承了基於套接字(socket)的程序間的通訊機制。這樣程序間的通訊就不侷限於單臺計算機了,實現了網路通訊。
程序的通訊機制主要有:管道、有名管道、訊息佇列、訊號量、共享空間、訊號、套接字。

1.訊號

訊號是在軟體層次上對中斷機制的一種模擬,在原理上,一個程序收到一個訊號與處理器收到一箇中斷請求可以說是一樣的。訊號是非同步的,一個程序不必通過任何操作來等待訊號的到達,事實上,程序也不知道訊號到底什麼時候到達。訊號是程序間通訊機制中唯一的非同步通訊機制,可以看作是非同步通知,通知接收訊號的程序有哪些事情發生了。訊號機制經過POSIX實時擴充套件後,功能更加強大,除了基本通知功能外,還可以傳遞附加資訊。訊號事件的發生有兩個來源:硬體來源(比如我們按下了鍵盤或者其它硬體故障);軟體來源。 訊號分為可靠訊號和不可靠訊號,實時訊號和非實時訊號。 程序有三種方式響應訊號:
  • 忽略訊號
  • 捕捉訊號
  • 執行預設操作

2.訊號量

訊號量也可以說是一個計數器,常用來處理程序或執行緒同步的問題,特別是對臨界資源的訪問同步問題。臨界資源:為某一時刻只能由一個程序或執行緒操作的資源,當訊號量的值大於或等於0時,表示可以供併發程序訪問的臨界資源數,當小於0時,表示正在等待使用臨界資源的程序數。更重要的是,訊號量的值僅能由PV操作來改變。

3.訊息佇列

訊息佇列是存放在核心中的訊息連結串列,每個訊息佇列由訊息佇列識別符號標識,於管道不同的是,訊息佇列存放在核心中,只有在核心重啟時才能刪除一個訊息佇列,核心重啟也就是系統重啟,同樣訊息佇列的大小也是受限制的。

4.共享記憶體

共享記憶體就是分配一塊能被其他程序訪問的記憶體。共享記憶體可以說是最有用的程序間通訊方式,也是最快的IPC形式。首先說下在使用共享記憶體區前,必須通過系統函式將其附加到程序的地址空間或說為對映到程序空間。兩個不同程序A、B共享記憶體的意思是,同一塊實體記憶體被對映到 程序A、B各自的程序地址空間。程序A可以即時看到程序B對共享記憶體中資料的更新,反之亦然。由於多個程序共享同一塊記憶體區域,必然需要某種同步機制,互 斥鎖和訊號量都可以。採用共享記憶體通訊的一個顯而易 見的好處是效率高,因為程序可以直接讀寫記憶體,而不需要任何資料的拷貝。對於像管道和訊息佇列等通訊方式,則需要在核心和使用者空間進行四次的資料拷貝,而 共享記憶體則只拷貝兩次資料[1]:一次從輸入檔案到共享記憶體區,另一次從共享記憶體區到輸出檔案。實際上,程序之間在共享記憶體時,並不總是讀寫少量資料後就 解除對映,有新的通訊時,再重新建立共享記憶體區域。而是保持共享區域,直到通訊完畢為止,這樣,資料內容一直儲存在共享記憶體中,並沒有寫回檔案。共享記憶體 中的內容往往是在解除對映時才寫回檔案的。因此,採用共享記憶體的通訊方式效率是非常高的。

5.管道

管道傳遞資料是單向性的,只能從一方流向另一方,也就是一種半雙工的通訊方式;只用於有親緣關係的程序間的通訊,親緣關係也就是父子程序或兄弟程序;沒有名字並且大小受限,傳輸的是無格式的流,所以兩程序通訊時必須約定好資料通訊的格式。管道它就像一個特殊的檔案,但這個檔案之存在於記憶體中,在建立管道時,系統為管道分配了一個頁面作為資料緩衝區,程序對這個資料緩衝區進行讀寫,以此來完成通訊。其中一個程序只能讀一個只能寫,所以叫半雙工通訊,為什麼一個只能讀一個只能寫呢?因為寫程序是在緩衝區的末尾寫入,讀程序是在緩衝區的頭部讀取,他們各自 的資料結構不同,所以功能不同。

6.命名管道

命名管道(NamedPipe)是伺服器程序和一個或多個客戶程序之間通訊的單向或雙向管道。不同於匿名管道的是:命名管道可以在不相關的程序之間和不同計算機之間使用,伺服器建立命名管道時給它指定一個名字,任何程序都可以通過該名字開啟管道的另一端,根據給定的許可權和伺服器程序通訊。命名管道提供了相對簡單的程式設計介面,使通過網路傳輸資料並不比同一計算機上兩程序之間通訊更困難,不過如果要同時和多個程序通訊它就力不從心了。
命名管道不同與管道只能在具有親緣關係的程序間通訊了。它提供了一個路徑名與之關聯,有了自己的傳輸格式。 命名管道和管道的不同之處還有一點是,有名管道是個裝置檔案,儲存在檔案系統中,沒有親緣關係的程序也可以訪問,但是它要按照先進先出的原則讀取資料。同樣也是單雙工的。

7.套接字

套接字也是一種程序間通訊機制,與其他通訊機制不同的是,它可用於不同主機間的程序通訊。

二、執行緒間通訊

執行緒間通訊:由於多執行緒共享地址空間和資料空間,所以多個執行緒間的通訊是一個執行緒的資料可以直接提供給其他執行緒使用,而不必通過作業系統(也就是核心的排程)。

1.鎖機制

包括互斥鎖、條件變數、讀寫鎖;  互斥鎖提供了以排他方式防止資料結構被併發修改的方法。 使用條件變數可以以原子的方式阻塞程序,直到某個特定條件為真為止。對條件的測試是在互斥鎖的保護下進行的。條件變數始終與互斥鎖一起使用。
讀寫鎖允許多個執行緒同時讀共享資料,而對寫操作是互斥的。

2.訊號量機制(Semaphore)

包括無名執行緒訊號量和命名執行緒訊號量

3.訊號機制(Signal)

類似程序間的訊號處理
執行緒間的通訊目的主要是用於執行緒同步。所以執行緒沒有像程序通訊中的用於資料交換的通訊機制。

三、linux中程序間通訊和執行緒間通訊的區別

  1. linux中的程序,是有fork()系統呼叫建立的,程序間都有獨立的地址空間,他們之間不能直接通訊,必須通過一些IPC程序程序間通訊機制來完成。常見的IPC有:PIPE,命名管道,訊號,共享記憶體以及socket等;
  2. linux中的執行緒,是clone()系統呼叫建立的,一個程序下的執行緒間是共享記憶體空間的,故執行緒A可以之間訪問執行緒B中定義的變數,但是必須注意併發的情況;
  3. 另:“執行緒上下文”的規模要遠遠小於程序上下文

四、程序/執行緒間同步機制

臨界區(Critical Section)、互斥量(Mutex)、訊號量(Semaphore)、事件(Event)四種方式

1.臨界區

通過對多執行緒的序列化來訪問公共資源或一段程式碼,速度快,適合控制資料訪問。在任意時刻只允許一個執行緒對共享資源進行訪問,如果有多個執行緒試圖訪問公共資源,那麼在有一個執行緒進入後,其他試圖訪問公共資源的執行緒將被掛起,並一直等到進入臨界區的執行緒離開,臨界區在被釋放後,其他執行緒才可以搶佔。

2.互斥量

採用互斥物件機制。 只有擁有互斥物件的執行緒才有訪問公共資源的許可權,因為互斥物件只有一個,所以能保證公共資源不會同時被多個執行緒訪問。互斥不僅能實現同一應用程式的公共資源安全共享,還能實現不同應用程式的公共資源安全共享 .互斥量比臨界區複雜。因為使用互斥不僅僅能夠在同一應用程式不同執行緒中實現資源的安全共享,而且可以在不同應用程式的執行緒之間實現對資源的安全共享。

3.訊號量

它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目 .訊號量物件對執行緒的同步方式與前面幾種方法不同,訊號允許多個執行緒同時使用共享資源,這與作業系統中的PV操作相同。它指出了同時訪問共享資源的執行緒最大數目。它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。
PV操作及訊號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。訊號量S是一個整數,S大於等於零時代表可供併發程序使用的資源實體數,但S小於零時則表示正在等待使用共享資源的程序數。
   P操作申請資源:
  (1)S減1;
  (2)若S減1後仍大於等於零,則程序繼續執行;
  (3)若S減1後小於零,則該程序被阻塞後進入與該訊號相對應的佇列中,然後轉入程序排程。  
  V操作 釋放資源:
  (1)S加1;
  (2)若相加結果大於零,則程序繼續執行;
  (3)若相加結果小於等於零,則從該訊號的等待佇列中喚醒一個等待程序,然後再返回原程序繼續執行或轉入程序排程。

4.事 件 

通過通知操作的方式來保持執行緒的同步,還可以方便實現對多個執行緒的優先順序比較的操作 . 

5.總結

  1.  互斥量與臨界區的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越程序使用。所以建立互斥量需要的資源更多,所以如果只為了在程序內部是用的話使用臨界區會帶來速度上的優勢並能夠減少資源佔用量。因為互斥量是跨程序的互斥量一旦被建立,就可以通過名字開啟它。
  2. 互斥量(Mutex),訊號燈(Semaphore),事件(Event)都可以被跨越程序使用來進行同步資料操作,而其他的物件與資料同步操作無關,但對於程序和執行緒來講,如果程序和執行緒在執行狀態則為無訊號狀態,在退出後為有訊號狀態。所以可以使用WaitForSingleObject來等待程序和執行緒退出。
  3. 通過互斥量可以指定資源被獨佔的方式使用,但如果有下面一種情況通過互斥量就無法處理,比如現在一位使用者購買了一份三個併發訪問許可的資料庫系統,可以根據使用者購買的訪問許可數量來決定有多少個執行緒/程序能同時進行資料庫操作,這時候如果利用互斥量就沒有辦法完成這個要求,訊號燈物件可以說是一種資源計數器。 

①程式,程序,執行緒的區別


程式:程式是由一系列的指令和邏輯組成的一個靜態檔案(如cpp檔案),無論能不能執行,它都客觀的存在於儲存器中。


程序:程序是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位--來源於百度百科。如果你是初學者,可能你並不能真正地理解這句話。通俗地說,系統為特定的靜態程式分配好執行時需要的各種資源,這個時候系統會連帶地生成一個PCB(程序控制塊,一種資料結構)用來記錄程式執行時(這裡的執行並不是指程序的執行態)的各種資訊(如程序當前的狀態等),這個時候你的程式就可以運行了,只需要等待CPU對其的呼叫,我們用程序來稱呼其為程式的一次執行。


執行緒:在以前,程序是系統獨立排程和分派的基本單位,後面由於多道處理的出現,產生了併發的概念(不明白併發的話可以先看第②點),它加大了系統的容量與對硬體的利用率。我們知道,對於單處理器的機器來說,實現併發典型的方法便是使用分時,即CPU將時間片按特定演算法分發給各個程序,雖然總的計算次數可能並沒有發生什麼變化,但是由於CPU的計算速度越來越快,從巨集觀上來看,幾個程序就像是在同一時間段內執行的。於是,當程序A的時間用完了之後就要切換到另一個程序B,此時計算機需要為程序A儲存下結束時的狀態以便下一次從上一次結束處繼續執行,還需要為程序B的執行做各種準備工作,由於程序相對而言比較大,反覆切換會浪費很多的資源,所以人們想能不能將系統獨立排程和分派的基本單位做得更小,以減少程序切換所浪費的資源--於是執行緒出現了。現在,大部分的OS都是以執行緒為系統獨立排程和分派的基本單位。另外,程序是由一個或者多個執行緒組成,執行緒是程序中的一個實體,是被系統獨立排程和分派的基本單位,執行緒自己不擁有系統資源,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個程序的其它執行緒共享程序所擁有的全部資源。一個執行緒可以建立和撤消另一個執行緒,同一程序中的多個執行緒之間可以併發執行。


給大家舉一個例子:

假如你是一個很牛逼的科學家,至少是愛因斯坦那種,呵呵,某一天你突然產生了一個念頭--你要做一個機器人女朋友,她無所不能,大家可以盡情想象!一天之內你就將整個生產流程以及各種製造細節都記錄在了紙上程式)。儘管你很牛逼,但是你卻很孤傲,從不發表自己的發明,結果肯定就是你比較窮,於是你缺少各種原料來實現(資源)。上帝總是很眷顧你!於是第二天你就莫名其妙有了各種原料,開始著手於組建你的無所不能的機器人女友(程序)。當然製作的過程肯定是分得很細的,如製造頭,製造手等等(執行緒),你每花1分鐘的時間來製造頭就會花1分鐘的時間來製造手(併發)。最後,你的女朋友做好了,盡情地享受吧!


②併發,並行的區別


併發:同一時間段內交替執行多個程序(執行緒) 並行:同一時刻執行多個程序(執行緒)。很明顯,只有多處理器才能支援。
併發就像我們的大腦思考一樣,同一個時刻只能想一件事,但是在很短的一個時間段內我們可以三心二意。當然如果你長了幾個腦袋,那你就可以並行思考了呵呵。


③同步與非同步,阻塞與非阻塞方式


讓我們再來了解一下同步非同步阻塞非阻塞這個概念,加深對多執行緒程式設計的理解。
有了之前的概念,我們可以想象,當幾個執行緒或者程序在併發執行時,如果我們不加任何干預措施,那麼他們的執行順序是由系統當時的環境來決定的,所以不同時間段不同環境下執行的順序都會不盡相同,這便是非同步(有差異的步驟)。當然,同步肯定就是通過一定的措施,使得幾個執行緒或者程序總是按照一定順序來執行(總是按照相同的步驟)
當一個程序或者執行緒請求某一個資源而不得時,如I/O,便會進入阻塞狀態,一直等待。scanf()便是一個很好的例子,當程式執行到scanf()時,如果輸入快取區為空,那麼程式便會進入阻塞狀態等待我們從鍵盤輸入,這便是以阻塞的方式呼叫scanf()。 通過一定方法,我們可以將scanf()變成非阻塞的方式來執行。如給scanf()設定一個超時時間,如果時間到了還是沒有輸入那麼便跳過scanf(),這個時候我們就稱為用非阻塞的方式來呼叫scanf()。
對比可以發現,同步即阻塞。想要按照某特定順序來執行一系列過程,在上一個過程完成之前下一個過程必須等待,這就是阻塞在了這個地方。當同步執行的時候,會等待同步操作完成才會返回,否則會一直阻塞在同步操作處。
相反的,非同步即非阻塞,當非同步呼叫某個函式時,函式會立刻返回,而不會阻塞在那。 怎麼判斷非同步操作是否已經完成?通常有3種方式: 1.狀態:非同步操作完成時會將某個全域性變數置為特定值,可以通過輪詢判斷變數的值以確定是否操作完成。 2.通知:非同步操作完成會給呼叫者傳送特定訊號。 3.回撥:非同步操作完成時會呼叫回撥函式。
所以同步即阻塞,非同步即非阻塞。

執行緒程序的通訊和同步:

摘要

本文主要是為了總結作業系統裡面的程序與執行緒通訊。 作業系統的主要任務是管理計算機的軟體、硬體資源。現代作業系統的主要特點是多使用者和多工,也就是程式的並行執行,windows如此linux也是如此。所以作業系統就藉助於程序來管理計算機的軟、硬體資源,支援多工的並行執行。要並行執行就需要多程序、多執行緒。因此多程序和多執行緒間為了完成一定的任務,就需要進行一定的通訊。而執行緒間通訊又和程序間的通訊不同。由於程序的資料空間相對獨立而執行緒是共享資料空間的,彼此通訊機制也很不同。

一、程序間通訊

程序間的通訊,它的資料空間的獨立性決定了它的通訊相對比較複雜,需要通過作業系統。以前程序間的通訊只能是單機版的,現在作業系統都繼承了基於套接字(socket)的程序間的通訊機制。這樣程序間的通訊就不侷限於單臺計算機了,實現了網路通訊。
程序的通訊機制主要有:管道、有名管道、訊息佇列、訊號量、共享空間、訊號、套接字。

1.訊號

訊號是在軟體層次上對中斷機制的一種模擬,在原理上,一個程序收到一個訊號與處理器收到一箇中斷請求可以說是一樣的。訊號是非同步的,一個程序不必通過任何操作來等待訊號的到達,事實上,程序也不知道訊號到底什麼時候到達。訊號是程序間通訊機制中唯一的非同步通訊機制,可以看作是非同步通知,通知接收訊號的程序有哪些事情發生了。訊號機制經過POSIX實時擴充套件後,功能更加強大,除了基本通知功能外,還可以傳遞附加資訊。訊號事件的發生有兩個來源:硬體來源(比如我們按下了鍵盤或者其它硬體故障);軟體來源。 訊號分為可靠訊號和不可靠訊號,實時訊號和非實時訊號。 程序有三種方式響應訊號:
  • 忽略訊號
  • 捕捉訊號
  • 執行預設操作

2.訊號量

訊號量也可以說是一個計數器,常用來處理程序或執行緒同步的問題,特別是對臨界資源的訪問同步問題。臨界資源:為某一時刻只能由一個程序或執行緒操作的資源,當訊號量的值大於或等於0時,表示可以供併發程序訪問的臨界資源數,當小於0時,表示正在等待使用臨界資源的程序數。更重要的是,訊號量的值僅能由PV操作來改變。

3.訊息佇列

訊息佇列是存放在核心中的訊息連結串列,每個訊息佇列由訊息佇列識別符號標識,於管道不同的是,訊息佇列存放在核心中,只有在核心重啟時才能刪除一個訊息佇列,核心重啟也就是系統重啟,同樣訊息佇列的大小也是受限制的。

4.共享記憶體

共享記憶體就是分配一塊能被其他程序訪問的記憶體。共享記憶體可以說是最有用的程序間通訊方式,也是最快的IPC形式。首先說下在使用共享記憶體區前,必須通過系統函式將其附加到程序的地址空間或說為對映到程序空間。兩個不同程序A、B共享記憶體的意思是,同一塊實體記憶體被對映到 程序A、B各自的程序地址空間。程序A可以即時看到程序B對共享記憶體中資料的更新,反之亦然。由於多個程序共享同一塊記憶體區域,必然需要某種同步機制,互 斥鎖和訊號量都可以。採用共享記憶體通訊的一個顯而易 見的好處是效率高,因為程序可以直接讀寫記憶體,而不需要任何資料的拷貝。對於像管道和訊息佇列等通訊方式,則需要在核心和使用者空間進行四次的資料拷貝,而 共享記憶體則只拷貝兩次資料[1]:一次從輸入檔案到共享記憶體區,另一次從共享記憶體區到輸出檔案。實際上,程序之間在共享記憶體時,並不總是讀寫少量資料後就 解除對映,有新的通訊時,再重新建立共享記憶體區域。而是保持共享區域,直到通訊完畢為止,這樣,資料內容一直儲存在共享記憶體中,並沒有寫回檔案。共享記憶體 中的內容往往是在解除對映時才寫回檔案的。因此,採用共享記憶體的通訊方式效率是非常高的。

5.管道

管道傳遞資料是單向性的,只能從一方流向另一方,也就是一種半雙工的通訊方式;只用於有親緣關係的程序間的通訊,親緣關係也就是父子程序或兄弟程序;沒有名字並且大小受限,傳輸的是無格式的流,所以兩程序通訊時必須約定好資料通訊的格式。管道它就像一個特殊的檔案,但這個檔案之存在於記憶體中,在建立管道時,系統為管道分配了一個頁面作為資料緩衝區,程序對這個資料緩衝區進行讀寫,以此來完成通訊。其中一個程序只能讀一個只能寫,所以叫半雙工通訊,為什麼一個只能讀一個只能寫呢?因為寫程序是在緩衝區的末尾寫入,讀程序是在緩衝區的頭部讀取,他們各自 的資料結構不同,所以功能不同。

6.命名管道

命名管道(NamedPipe)是伺服器程序和一個或多個客戶程序之間通訊的單向或雙向管道。不同於匿名管道的是:命名管道可以在不相關的程序之間和不同計算機之間使用,伺服器建立命名管道時給它指定一個名字,任何程序都可以通過該名字開啟管道的另一端,根據給定的許可權和伺服器程序通訊。命名管道提供了相對簡單的程式設計介面,使通過網路傳輸資料並不比同一計算機上兩程序之間通訊更困難,不過如果要同時和多個程序通訊它就力不從心了。
命名管道不同與管道只能在具有親緣關係的程序間通訊了。它提供了一個路徑名與之關聯,有了自己的傳輸格式。 命名管道和管道的不同之處還有一點是,有名管道是個裝置檔案,儲存在檔案系統中,沒有親緣關係的程序也可以訪問,但是它要按照先進先出的原則讀取資料。同樣也是單雙工的。

7.套接字

套接字也是一種程序間通訊機制,與其他通訊機制不同的是,它可用於不同主機間的程序通訊。

二、執行緒間通訊

執行緒間通訊:由於多執行緒共享地址空間和資料空間,所以多個執行緒間的通訊是一個執行緒的資料可以直接提供給其他執行緒使用,而不必通過作業系統(也就是核心的排程)。

1.鎖機制

包括互斥鎖、條件變數、讀寫鎖;  互斥鎖提供了以排他方式防止資料結構被併發修改的方法。 使用條件變數可以以原子的方式阻塞程序,直到某個特定條件為真為止。對條件的測試是在互斥鎖的保護下進行的。條件變數始終與互斥鎖一起使用。
讀寫鎖允許多個執行緒同時讀共享資料,而對寫操作是互斥的。

2.訊號量機制(Semaphore)

包括無名執行緒訊號量和命名執行緒訊號量

3.訊號機制(Signal)

類似程序間的訊號處理
執行緒間的通訊目的主要是用於執行緒同步。所以執行緒沒有像程序通訊中的用於資料交換的通訊機制。

三、linux中程序間通訊和執行緒間通訊的區別

  1. linux中的程序,是有fork()系統呼叫建立的,程序間都有獨立的地址空間,他們之間不能直接通訊,必須通過一些IPC程序程序間通訊機制來完成。常見的IPC有:PIPE,命名管道,訊號,共享記憶體以及socket等;
  2. linux中的執行緒,是clone()系統呼叫建立的,一個程序下的執行緒間是共享記憶體空間的,故執行緒A可以之間訪問執行緒B中定義的變數,但是必須注意併發的情況;
  3. 另:“執行緒上下文”的規模要遠遠小於程序上下文

四、程序/執行緒間同步機制

臨界區(Critical Section)、互斥量(Mutex)、訊號量(Semaphore)、事件(Event)四種方式

1.臨界區

通過對多執行緒的序列化來訪問公共資源或一段程式碼,速度快,適合控制資料訪問。在任意時刻只允許一個執行緒對共享資源進行訪問,如果有多個執行緒試圖訪問公共資源,那麼在有一個執行緒進入後,其他試圖訪問公共資源的執行緒將被掛起,並一直等到進入臨界區的執行緒離開,臨界區在被釋放後,其他執行緒才可以搶佔。

2.互斥量

採用互斥物件機制。 只有擁有互斥物件的執行緒才有訪問公共資源的許可權,因為互斥物件只有一個,所以能保證公共資源不會同時被多個執行緒訪問。互斥不僅能實現同一應用程式的公共資源安全共享,還能實現不同應用程式的公共資源安全共享 .互斥量比臨界區複雜。因為使用互斥不僅僅能夠在同一應用程式不同執行緒中實現資源的安全共享,而且可以在不同應用程式的執行緒之間實現對資源的安全共享。

3.訊號量

它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目 .訊號量物件對執行緒的同步方式與前面幾種方法不同,訊號允許多個執行緒同時使用共享資源,這與作業系統中的PV操作相同。它指出了同時訪問共享資源的執行緒最大數目。它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。
PV操作及訊號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。訊號量S是一個整數,S大於等於零時代表可供併發程序使用的資源實體數,但S小於零時則表示正在等待使用共享資源的程序數。
   P操作申請資源:
  (1)S減1;
  (2)若S減1後仍大於等於零,則程序繼續執行;
  (3)若S減1後小於零,則該程序被阻塞後進入與該訊號相對應的佇列中,然後轉入程序排程。  
  V操作 釋放資源:
  (1)S加1;
  (2)若相加結果大於零,則程序繼續執行;
  (3)若相加結果小於等於零,則從該訊號的等待佇列中喚醒一個等待程序,然後再返回原程序繼續執行或轉入程序排程。

4.事 件 

通過通知操作的方式來保持執行緒的同步,還可以方便實現對多個執行緒的優先順序比較的操作 . 

5.總結

  1.  互斥量與臨界區的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越程序使用。所以建立互斥量需要的資源更多,所以如果只為了在程序內部是用的話使用臨界區會帶來速度上的優勢並能夠減少資源佔用量。因為互斥量是跨程序的互斥量一旦被建立,就可以通過名字開啟它。
  2. 互斥量(Mutex),訊號燈(Semaphore),事件(Event)都可以被跨越程序使用來進行同步資料操作,而其他的物件與資料同步操作無關,但對於程序和執行緒來講,如果程序和執行緒在執行狀態則為無訊號狀態,在退出後為有訊號狀態。所以可以使用WaitForSingleObject來等待程序和執行緒退出。
  3. 通過互斥量可以指定資源被獨佔的方式使用,但如果有下面一種情況通過互斥量就無法處理,比如現在一位使用者購買了一份三個併發訪問許可的資料庫系統,可以根據使用者購買的訪問許可數量來決定有多少個執行緒/程序能同時進行資料庫操作,這時候如果利用互斥量就沒有辦法完成這個要求,訊號燈物件可以說是一種資源計數器。