什麼是進程?什麼是線程?總結

1.什麼是進程?什麼是線程?

進程是表示資源分配的基本單位,又是調度運行的基本單位。例如,用戶運行自己的程序,系統就創建一個進程,併爲它分配資源,包括各種表格、內存空間、磁盤空間、I/O設備等。然後,把該進程放人進程的就緒隊列。進程調度程序選中它,爲它分配CPU以及其它有關資源,該進程才真正運行。所以,進程是系統中的併發執行的單位。
MacWindows NT等採用微內核結構的操作系統中,進程的功能發生了變化:它只是資源分配的單位,而不再是調度運行的單位。在微內核系統中,真正調度運行的基本單位是線程。因此,實現併發功能的單位是線程。
線程概念
  線程是進程中執行運算的最小單位,亦即執行處理機調度的基本單位。如果把進程理解爲在邏輯上操作系統所完成的任務,那麼線程表示完成該任務的許多可能的子任務之一。例如,假設用戶啓動了一個窗口中的數據庫應用程序,操作系統就將對數據庫的調用表示爲一個進程。假設用戶要從數據庫中產生一份工資單報表,並傳到一個文件中,這是一個子任務;在產生工資單報表的過程中,用戶又可以輸人數據庫查詢請求,這又是一個子任務。這樣,操作系統則把每一個請求――工資單報表和新輸人的數據查詢表示爲數據庫進程中的獨立的線程。線程可以在處理器上獨立調度執行,這樣,在多處理器環境下就允許幾個線程各自在單獨處理器上進行。操作系統提供線程就是爲了方便而有效地實現這種併發性。

 舉個例子來說多線程就像是火車上的每節車廂,而進程就是火車。

2.多進程和多線程的區別?

我們從各個方面來看待這個問題,由下面的圖片說明:

對比維度

多進程

多線程

總結

數據共享、同步

數據共享複雜,需要用IPC;數據是分開的,同步簡單

因爲共享進程數據,數據共享簡單,但也是因爲這個原因導致同步複雜

各有優勢

內存、CPU

佔用內存多,切換複雜,CPU利用率低

佔用內存少,切換簡單,CPU利用率高

線程佔優

創建銷燬、切換

創建銷燬、切換複雜,速度慢

創建銷燬、切換簡單,速度很快

線程佔優

編程、調試

編程簡單,調試簡單

編程複雜,調試複雜

進程佔優

可靠性

進程間不會互相影響

一個線程掛掉將導致整個進程掛掉

進程佔優

分佈式

適應於多核、多機分佈式;如果一臺機器不夠,擴展到多臺機器比較簡單

適應於多核分佈式

進程佔優

3.進程之間的通信方式以及優缺點?

1)管道
管道分爲有名管道和無名管道
無名管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關係的進程間使用.進程的親緣關係一般指的是父子關係。無明管道一般用於兩個不同進程之間的通信。當一個進程創建了一個管道,並調用fork創建自己的一個子進程後,父進程關閉讀管道端,子進程關閉寫管道端,這樣提供了兩個進程之間數據流動的一種方式。
有名管道也是一種半雙工的通信方式,但是它允許無親緣關係進程間的通信。

無名管道:優點:簡單方便;缺點:1)侷限於單向通信2)只能創建在它的進程以及其有親緣關係的進程之間;3)緩衝區有限;
有名管道:優點:可以實現任意關係的進程間的通信;缺點:1)長期存於系統中,使用不當容易出錯;2)緩衝區有限
2)信號量
信號量是一個計數器,可以用來控制多個線程對共享資源的訪問.,它不是用於交換大批數據,而用於多線程之間的同步.它常作爲一種鎖機制,防止某進程在訪問資源時其它進程也訪問該資源.因此,主要作爲進程間以及同一個進程內不同線程之間的同步手段.
優點:可以同步進程;缺點:信號量有限

3)信號
信號是一種比較複雜的通信方式,用於通知接收進程某個事件已經發生.

4)
消息隊列
消息隊列是消息的鏈表,存放在內核中並由消息隊列標識符標識.消息隊列克服了信號傳遞信息少,管道只能承載無格式字節流以及緩衝區大小受限等特點.消息隊列是UNIX下不同進程之間可實現共享資源的一種機制,UNIX允許不同進程將格式化的數據流以消息隊列形式發送給任意進程.對消息隊列具有操作權限的進程都可以使用msget完成對消息隊列的操作控制.通過使用消息類型,進程可以按任何順序讀信息,或爲消息安排優先級順序.

優點:可以實現任意進程間的通信,並通過系統調用函數來實現消息發送和接收之間的同步,無需考慮同步問題,方便;缺點:信息的複製需要額外消耗CPU的時間,不適宜於信息量大或操作頻繁的場合

5)共享內存
共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問.共享內存是最快的IPC(進程間通信)方式,它是針對其它進程間通信方式運行效率低而專門設計的.它往往與其他通信機制,如信號量,配合使用,來實現進程間的同步與通信.

優點:無須複製,快捷,信息量大;缺點:1)通信是通過將共無法實現享空間緩衝區直接附加到進程的虛擬地址空間中來實現的,因此進程間的讀寫操作的同步問題;2)利用內存緩衝區直接交換信息,內存的實體存在於計算機中,只能同一個計算機系統中的諸多進程共享,不方便網絡通信

6)套接字:可用於不同及其間的進程通信
優點:1)傳輸數據爲字節級,傳輸數據可自定義,數據量小效率高;2)傳輸數據時間短,性能高;3) 適合於客戶端和服務器端之間信息實時交互;4) 可以加密,數據安全性強
缺點:1) 需對傳輸的數據進行解析,轉化成應用級的數據。

4.線程之間的通信方式?

 # 鎖機制:包括互斥鎖、條件變量、讀寫鎖
   *互斥鎖提供了以排他方式防止數據結構被併發修改的方法。
   *讀寫鎖允許多個線程同時讀共享數據,而對寫操作是互斥的。
   *條件變量可以以原子的方式阻塞進程,直到某個特定條件爲真爲止。對條件的測試是在互斥鎖的保護下進行的。條件變量始終與互斥鎖一起使用。
信號量機制(Semaphore):包括無名線程信號量和命名線程信號量
信號機制(Signal):類似進程間的信號處理
    線程間的通信目的主要是用於線程同步,所以線程沒有像進程通信中的用於數據交換的通信機制。

5.什麼時候用多線程?什麼時候用多進程?

1)需要頻繁創建銷燬的優先用線程
原因請看上面的對比。
這種原則最常見的應用就是Web服務器了,來一個連接建立一個線程,斷了就銷燬線程,要是用進程,創建和銷燬的代價是很難承受的
2)需要進行大量計算的優先使用線程
所謂大量計算,當然就是要耗費很多CPU,切換頻繁了,這種情況下線程是最合適的。
這種原則最常見的是圖像處理、算法處理。
3)強相關的處理用線程,弱相關的處理用進程
什麼叫強相關、弱相關?理論上很難定義,給個簡單的例子就明白了。
一般的Server需要完成如下任務:消息收發、消息處理。消息收發消息處理就是弱相關的任務,而消息處理裏面可能又分爲消息解碼業務處理,這兩個任務相對來說相關性就要強多了。因此消息收發消息處理可以分進程設計,消息解碼業務處理可以分線程設計。
當然這種劃分方式不是一成不變的,也可以根據實際情況進行調整。
4)可能要擴展到多機分佈的用進程,多核分佈的用線程
原因請看上面對比。
5)都滿足需求的情況下,用你最熟悉、最拿手的方式
至於數據共享、同步編程、調試可靠性這幾個維度的所謂的複雜、簡單應該怎麼取捨,我只能說:沒有明確的選擇方法。但我可以告訴你一個選擇原則:如果多進程和多線程都能夠滿足要求,那麼選擇你最熟悉、最拿手的那個。

1、線程的基本概念、線程的基本狀態與狀態之間的關係?

線程是進程裏面一個執行上下文,或者是執行序列。線程是進程級別上的多道編程。同一進程的多個線程共享一塊內存空間和一組系統資源,線程本身有一個供程序執行時的堆棧。線程之間切換快,無需陷入內核態。

線程狀態

 

阻塞狀態分分爲三種:等待阻塞(wait)、同步阻塞( 加鎖 )、其他阻塞(睡眠)

新建狀態

當用new操作符創建一個線程時。此時程序還沒有開始運行線程中的代碼。

就緒狀態

一個新創建的線程並不自動開始運行,要執行線程,必須調用線程的start()方法。當線程對象調用start()方法即啓動了線程,start()方法創建線程運行的系統資源,並調度線程運行run()方法。當start()方法返回後,線程就處於就緒狀態。處於就緒狀態的線程並不一定立即運行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間纔可以運行線程。因爲在單CPU的計算機系統中,不可能同時運行多個線程,一個時刻僅有一個線程處於運行狀態。因此此時可能有多個線程處於就緒狀態。對多個處於就緒狀態的線程是由Java運行時系統的線程調度程序來調度的。

運行狀態(runing

當線程獲得 CPU時間後,它才進圖運行狀態,真正開始執行run()方法。

阻塞狀態(blocked

線程運行過程中,可能由於各種原因進入阻塞狀態:

線程通過調用sleep方法進入睡眠狀態;

線程調用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調用者;

線程試圖得到一個鎖,而該鎖正被其他線程持有;

線程在等待某個觸發條件;

所謂阻塞狀態是正在運行的線程沒有運行結束,暫時讓出CPU,這時其他處於就緒狀態的線程就可以獲得CPU時間,進入運行狀態。

死亡狀態(dead

有兩個原因會導致線程死亡:

run方法正常退出而自然死亡;

一個未捕獲的異常終止了run方法而使線程猝死;

爲了確定線程在當前是否存活着(就是要麼是可運行的,要麼是被阻塞了),需要使用isAlive方法,如果是可運行或被阻塞,這個方法返回true;如果線程仍舊是new狀態且不是可運行的,或者線程死亡了,則返回false

2、進程與線程的區別:

一個進程至少有一個主執行線程,它無需由用戶去主動創建,是由系統自動創建的。用戶根據需要在應用程序中創建其他線程,多個線程併發地運行在同一個進程。一個進程彙總的所有線程都在該進程的虛擬地址空間彙總,共同使用這些虛擬地址空間、全局變量和系統資源,所以線程間的通訊非常方便,多線程技術的應用也較爲廣泛。

基於進程的多任務處理是程序的併發執行。基於線程的多任務處理是同一程序的片段的併發執行;

地址空間:同一進程的線程共享本進程的地址空間,而進程之間則是獨立的地址空間;

資源擁有:同一進程內的線程共享本進程的資源如內存、I/Ocpu等,但是進程之間的資源是獨立的;

一個進程奔潰後,在保護模式下不會對其他進程產生影響,但是一個線程崩潰則整個進程都死掉,所以多進程要比多線程健壯;

進程切換時,消耗資源大,效率高,所以涉及到頻繁切換時,使用線程要好於進程;

執行過程:每個獨立的進程有一個程序運行的入口、順序執行序列和程序入口。但是線程不能獨立執行,必須依存於應用程序中,有應用程序提供多個線程執行控制。

線程是處理器調度的基本單位,但進程不是。

3、多線程有幾種實現方法

C++創建多線程的三種方式:

1.CreateThread()

CreateThread()windowsAPI函數,提供操作系統級別的創建線程的操作,且僅限於工作者線程。不調用MFCRTL函數(標準C語言函數),即只調用win32API時,可以 CreateThread。在使用過程中要考慮到進程撿的同步與互斥關係(防止死鎖)。

線程函數定義爲: DWORD WINAPI _yourThreradFun(LPVOID)

頭文件 <windows.h>

創建線程API

 

  1.  1 HANDLE CreateThread(
  2.  2     __in   SEC_ATTRS
  3.  3     SecurityAttributes,    //線程安全屬性
  4.  4     __in   ULONG
  5.  5     StackSize,        // 堆棧大小
  6.  6     __in   SEC_THREAD_START
  7.  7     StartFunction,    // 線程函數
  8.  8     __in   PVOID
  9.  9     ThreadParameter,  // 線程參數
  10. 10     __in   ULONG
  11. 11     CreationFlags,    // 線程創建屬性
  12. 12     __out  PULONG
  13. 13     ThreadId          // 線程ID
  14. 14     );

使用步驟:

  1. HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);
  2. CloseHandle(hThread);

2、互斥API:互斥量實現

 

  1.  1 HANDLE CreateMutex(
  2.  2     LPSECURITY_ATTRIBUTES lpMutexAttributes,
  3.  3     BOOL bInitialOwner,                       // 指定該資源初始是否歸屬創建它的進程
  4.  4     LPCTSTR lpName                            // 指定資源的名稱     
  5.  5     );
  6.  6
  7.  7 BOOL ReleaseMutex(
  8.  8     HANDLE hMutex   // 該函數用於釋放一個獨佔資源,進程一旦釋放該資源,該資源就不再屬於它了
  9.  9     );
  10. 10
  11. 11 DWORD WaitForSingleObject(
  12. 12     HANDLE hHandle,        // 指定所申請的資源的句柄
  13. 13     DWORD dwMilliseconds   // 一般指定爲INFINITE,表示如果沒有申請到資源就一直等待該資源
  14. 14     );

3、互斥API:臨界區實現

  1. 1 CRITICAL_SECTION cs;
  2. 2 InitializeCriticalSection(&cs);
  3. 3 EnterCriticalSection(&cs);
  4. 4 LeaveCriticalSection(&cs);
  5. 5 DeleteCriticalSection(&cs);
  6.  

例子:

 

  1.  #include <iostream>  
  2.  #include <windows.h>  
  3.  using namespace std;
  4.  
  5.  HANDLE hMutex;
  6.  
  7.  DWORD WINAPI Fun(LPVOID lpParamter)
  8.  {
  9.      while (1) {
  10.          WaitForSingleObject(hMutex, INFINITE);
  11.          cout << "Fun display!" << endl;
  12.          Sleep(1000);
  13.          ReleaseMutex(hMutex);
  14.      }
  15.  }
  16.  
  17.  int main()
  18.  {
  19.      HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NUL
  20.      hMutex = CreateMutex(NULL, FALSE, "screen");
  21.      CloseHandle(hThread);
  22.      while (1) {
  23.          WaitForSingleObject(hMutex, INFINITE);
  24.          cout << "main display!" << endl;
  25.          Sleep(2000);
  26.          ReleaseMutex(hMutex);
  27.      }
  28.  
  29.      return 0;
  30.  }
  31.  

 

4、多線程同步和互斥實現方式

當有多個線程的時候,經常需要去同步這些線程以訪問同一個數據或資源。例如,假設有一個程序,其中一個線程用於把文件讀到內存,而另一個線程用於統計文件中的字符數。當然,在把整個文件調入內存之前,統計它的計數是沒有意義的。但是,由於每個操作都有自己的線程,操作系統會把兩個線程當作是互不相干的任務分別執行,這樣就可能在沒有把整個文件裝入內存時統計字數。爲解決此問題,你必須使兩個線程同步工作。

所謂同步,是指在不同進程之間的若干程序片斷,它們的運行必須嚴格按照規定的某種先後次序來運行,這種先後次序依賴於要完成的特定的任務。如果用對資源的訪問來定義的話,同步是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源。

所謂互斥,是指散佈在不同進程之間的若干程序片斷,當某個進程運行其中一個程序片段時,其它進程就不能運行它們之中的任一程序片段,只能等到該進程運行完這個程序片段後纔可以運行。如果用對資源的訪問來定義的話,互斥某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。

實現方式:

線程間的同步方法大體可分爲兩類:用戶模式和內核模式。內核模式就是指利用系統內核對象的單一性來進行同步,使用時需要切換內核態與用戶態,而用戶模式就是不需要切換到內核態,只在用戶態完成操作。

用戶模式下的方法有:原子操作(例如一個單一的全局變量),臨界區。

內核模式下的方法有:事件,信號量,互斥量。

1、臨界區:通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問(可能造成競爭的共享資源) 
2
、互斥量:爲協調共同對一個共享資源的單獨訪問而設計的。 
3
、信號量:爲控制一個具有有限數量用戶資源而設計。 
4
、事 :用來通知線程有一些事件已發生,從而啓動後繼任務的開始。

同步的目的:多線程程序 的執行結果有可能是不確定的---》爲了消除不確定,產生了線程同步,即就是不管線程之間的執行如何穿梭,其運行結果都是正確的。

5、多線程同步和互斥有何異同,在什麼情況下分別使用它們?

線程同步是指線程之間所具有的一種制約關係,一個線程的執行依賴另一個線程的消息,當它沒有得到另一個線程的消息時應等待,直到消息到達時才被喚醒。

線程互斥是指對於共享的進程系統資源,在各單個線程訪問時的排它性。當有若干個線程都要使用某一共享資源時,任何時刻最多隻允許一個線程去使用,其它要使用該資源的線程必須等待,直到佔用資源者釋放該資源。線程互斥可以看成是一種特殊的線程同步(下文統稱爲同步)。

線程同步解決多線程併發問題:

 

幾種內核對象中,除了互斥量,沒有任何一個會記住自己是哪個線程等待成功的。

互斥量和關鍵段的比較:

1)關鍵段只適用於同一個進程,互斥量可適用與不同的進程

2)關鍵段的效率更高

3)關鍵段不安全,而互斥量更安全;

假如把整條道路看成是一個【進程】的話,那麼馬路中間白色虛線分隔開來的各個車道就是進程中的各個【線程】了。
  這些線程(車道)共享了進程(道路)的公共資源(土地資源)
  這些線程(車道)必須依賴於進程(道路),也就是說,線程不能脫離於進程而存在(就像離開了道路,車道也就沒有意義了)
  這些線程(車道)之間可以併發執行(各個車道你走你的,我走我的),也可以互相同步(某些車道在交通燈亮時禁止繼續前行或轉彎,必須等待其它車道的車輛通行完畢)
  這些線程(車道)之間依靠代碼邏輯(交通燈)來控制運行,一旦代碼邏輯控制有誤(死鎖,多個線程同時競爭唯一資源),那麼線程將陷入混亂,無序之中。
  這些線程(車道)之間誰先運行是未知的,只有在線程剛好被分配到CPU時間片(交通燈變化)的那一刻才能知道。
  注:
  由於用於互斥的信號量sem與所有的併發進程有關,所以稱之爲公有信號量。公有信號量的值反映了公有資源的數量。只要把臨界區置於P(sem)V(sem)之間,即可實現進程間的互斥。就象火車中的每節車廂只有一個衛生間,該車廂的所有旅客共享這個公有資源:衛生間,所以旅客間必須互斥進入衛生間,只要把衛生間放在P(sem)V(sem)之間,就可以到達互斥的效果。

多線程在筆試面試中經常出現,下面列出一些公司的多線程筆試面試題。首先是一些概念性的問答題,這些是多線程的基礎知識,經常出現在面試中的第一輪面試(我參加2011年騰訊研究院實習生招聘時就被問到了幾個概念性題目)。然後是一些選擇題,這些一般在筆試時出現,雖然不是太難,但如果在選擇題上花費大多時間無疑會對後面的編程題造成影響,因此必須迅速的解決掉。最後是綜合題即難一些的問答題或是編程題。這種題目當然是最難解決了,要麼會引來面試官的追問,要麼就很容易考慮不周全,因此解決這類題目時一定要考慮全面和細緻。

下面就來看看這三類題目吧。

   一。概念性問答題

   第一題:線程的基本概念、線程的基本狀態及狀態之間的關係?

概念:線程是進程中執行運算的最小單位,是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創建和撤消另一個線程,同一進程中的多個線程之間可以併發執行。

    好處 

1)易於調度。

               2)提高併發性。通過線程可方便有效地實現併發性。進程可創建多個線程來執行同一程序的不同部分。

               3)開銷少。創建線程比創建進程要快,所需開銷很少。。

               4)利於充分發揮多處理器的功能。通過創建多線程進程,每個線程在一個處理器上運行,從而實現應用程序的併發性,使每個處理器都得到充分運行。

狀態:運行、阻塞、掛起阻塞、就緒、掛起就緒

    狀態之間的轉換:準備就緒的進程,被CPU調度執行,變成運行態;

                                 運行中的進程,進行I/O請求或者不能得到所請求的資源,變成阻塞態;

                                 運行中的進程,進程執行完畢(或時間片已到),變成就緒態;

                                 將阻塞態的進程掛起,變成掛起阻塞態,當導致進程阻塞的I/O操作在用戶重啓進程前完成(稱之爲喚醒),掛起阻塞態變成掛起就緒態,當用戶在I/O操作結束之前重啓進程,掛起阻塞態變成阻塞態;

                                 將就緒(或運行)中的進程掛起,變成掛起就緒態,當該進程恢復之後,掛起就緒態變成就緒態;                

    第二題:線程與進程的區別?

   這個題目問到的概率相當大,計算機專業考研中也常常考到。要想全部答出比較難。

進程和線程的關係:

    1)一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程。

    2)資源分配給進程,同一進程的所有線程共享該進程的所有資源。

    3)處理機分給線程,即真正在處理機上運行的是線程。

    4)線程在執行過程中,需要協作同步。不同進程的線程間要利用消息通信的辦法實現同步。線程是指進程內的一個執行單元,也是進程內的可調度實體.

進程與線程的區別:

    1)調度:線程作爲調度和分配的基本單位,進程作爲擁有資源的基本單位

    2)併發性:不僅進程之間可以併發執行,同一個進程的多個線程之間也可併發執行

    3)擁有資源:進程是擁有資源的一個獨立單位,線程不擁有系統資源,但可以訪問隸屬於進程的資源.

    4)系統開銷:在創建或撤消進程時,由於系統都要爲之分配和回收資源,導致系統的開銷明顯大於創建或撤消線程時的開銷。

   第三題:多線程有幾種實現方法,都是什麼?

C++中多線程實現方法:

windows下通過api CreateThreadlinux下則常用pthread庫,這些都是最底層的實現,最新的C++11標準裏增加了std::thread多線程庫,使用第三方庫的話就更多了,比如boostthread等等,不推薦使用vc自家的_beginthread,尤其有跨平臺需求的時候。

JAVA中實現多線程的方法:

 1. 繼承 Thread 
    2. 實現 Runnable 接口再 new Thread(YourRunnableOjbect) 推薦
 

   第四題:多線程同步和互斥有幾種實現方法,都是什麼?

   2011年迅雷校園招聘時的一面和二面都被問到這個題目,回答的好將會給面試成績加不少分。

   線程間的同步方法大體可分爲兩類:用戶模式和內核模式。顧名思義,內核模式就是指利用系統內核對象的單一性來進行同步,使用時需要切換內核態與用戶態,而用戶模式就是不需要切換到內核態,只在用戶態完成操作。
用戶模式下的方法有:原子操作(例如一個單一的全局變量),臨界區。內核模式下的方法有:事件,信號量,互斥量。

 

   第五題:多線程同步和互斥有何異同,在什麼情況下分別使用他們?舉例說明。

當有多個線程的時候,經常需要去同步這些線程以訪問同一個數據或資源。例如,假設有一個程序,其中一個線程用於把文件讀到內存,而另一個線程用於統計文件中的字符數。當然,在把整個文件調入內存之前,統計它的計數是沒有意義的。但是,由於每個操作都有自己的線程,操作系統會把兩個線程當作是互不相干的任務分別執行,這樣就可能在沒有把整個文件裝入內存時統計字數。爲解決此問題,你必須使兩個線程同步工作。

      所謂同步,是指散步在不同進程之間的若干程序片斷,它們的運行必須嚴格按照規定的某種先後次序來運行,這種先後次序依賴於要完成的特定的任務。如果用對資源的訪問來定義的話,同步是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源。

        所謂互斥,是指散佈在不同進程之間的若干程序片斷,當某個進程運行其中一個程序片段時,其它進程就不能運行它們之中的任一程序片段,只能等到該進程運行完這個程序片段後纔可以運行。如果用對資源的訪問來定義的話,互斥某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。

     第六題:進程間通信的方式?

    1)管道(pipe)及有名管道(named pipe):管道可用於具有親緣關係的父子進程間的通信,有名管道除了具有管道所具有的功能外,它還允許無親緣關係進程間的通信。

    2)信號(signal):信號是在軟件層次上對中斷機制的一種模擬,它是比較複雜的通信方式,用於通知進程有某事件發生,一個進程收到一個信號與處理器收到一箇中斷請求效果上可以說是一致的。

    3)消息隊列(message queue):消息隊列是消息的鏈接表,它克服了上兩種通信方式中信號量有限的缺點,具有寫權限得進程可以按照一定得規則向消息隊列中添加新信息;對消息隊列有讀權限得進程則可以從消息隊列中讀取信息。

    4)共享內存(shared memory):可以說這是最有用的進程間通信方式。它使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數據得更新。這種方式需要依靠某種同步操作,如互斥鎖和信號量等。

    5)信號量(semaphore):主要作爲進程之間及同一種進程的不同線程之間得同步和互斥手段。

    6)套接字(socket):這是一種更爲一般得進程間通信機制,它可用於網絡中不同機器之間的進程間通信,應用非常廣泛。

二。選擇題

   第一題(百度筆試題):

   以下多線程對int型變量x的操作,哪幾個不需要進行同步:

    A.x=y;      B. x++;    C.++x;    D. x=1;

  答案參見:http://blog.csdn.net/jjj19891128/article/details/24392229
 

    第二題(阿里巴巴筆試題)

   多線程中棧與堆是公有的還是私有的

    A:棧公有, 堆私有

    B:棧公有,堆公有

    C:棧私有, 堆公有D:棧私有,堆私有

一般來說棧是私有的

堆是共有的

但是你可以爲特定的線程創建私有的堆

堆和棧的區別如下:

 

堆很靈活,但是不安全。對於對象,我們要動態地創建、銷燬,不能說後創建的對象沒有銷燬,先前創建的對象就不能銷燬,那樣的話我們的程序就寸步難行,所以Java中用堆來存儲對象。而一旦堆中的對象被銷燬,我們繼續引用這個對象的話,就會出現著名的 NullPointerException,這就是堆的缺點——錯誤的引用邏輯只有在運行時纔會被發現。

 

棧不靈活,但是很嚴格,是安全的,易於管理。因爲只要上面的引用沒有銷燬,下面引用就一定還在,所以,在棧中,上面引用永遠可以通過下面引用來查找對象,同時如果確認某一區間的內容會一起存在、一起銷燬,也可以上下互相引用。在大部分程序中,都是先定義的變量、引用先進棧,後定義的後進棧,同時,區塊內部的變量、引用在進入區塊時壓棧,區塊結束時出棧,理解了這種機制,我們就可以很方便地理解各種編程語言的作用域的概念了,同時這也是棧的優點——錯誤的引用邏輯在編譯時就可以被發現。

 

總之,就是變量和對象的引用存儲在棧區中,而對象在存儲在堆中


 

三。綜合題

   第一題(臺灣某殺毒軟件公司面試題):

   Windows編程中互斥量與臨界區比較類似,請分析一下二者的主要區別。

        兩者都可以用於同一進程中不同子線程對資源的互斥訪問。

        互斥量是內核對象,因此還可以用於不同進程中子線程對資源的互斥訪問。

        互斥量可以很好的解決由於線程意外終止資源無法釋放的問題。

    第二題:

   一個全局變量tally,兩個線程併發執行(代碼段都是ThreadProc),問兩個線程都結束後,tally取值範圍。

    inttally = 0;//glable

    voidThreadProc()

    {

    forint i = 1; i <= 50;i++

    tally += 1;

    }

 答:[50,100]
 

   第三題(某培訓機構的練習題):

   子線程循環 10次,接着主線程循環 100次,接着又回到子線程循環 10次,接着再回到主線程又循環 100次,如此循環50次,試寫出代碼。

   第四題(迅雷筆試題):

   編寫一個程序,開啓3個線程,這3個線程的ID分別爲ABC,每個線程將自己的ID在屏幕上打印10遍,要求輸出結果必須按ABC的順序顯示;如:ABCABC依次遞推。

   第五題(Google面試題)

   有四個線程1234.線程1的功能就是輸出1,線程2的功能就是輸出2,以此類推……現在有四個文件ABCD.初始都爲空。現要讓四個文件呈如下格式:

    A:1 2 3 4 1 2

    B:2 3 4 1 2 3

    C:3 4 1 2 3 4

    D:4 1 2 3 4 1

   請設計程序。

   下面的第六題與第七題也是在考研中或是程序員和軟件設計師認證考試中的熱門試題。

   第六題

   生產者消費者問題

   這是一個非常經典的多線程題目,題目大意如下:有一個生產者在生產產品,這些產品將提供給若干個消費者去消費,爲了使生產者和消費者能併發執行,在兩者之間設置一個有多個緩衝區的緩衝池,生產者將它生產的產品放入一個緩衝區中,消費者可以從緩衝區中取走產品進行消費,所有生產者和消費者都是異步方式運行的,但它們必須保持同步,即不允許消費者到一個空的緩衝區中取產品,也不允許生產者向一個已經裝滿產品且尚未被取走的緩衝區中投放產品。

   第七題

   讀者寫者問題

   這也是一個非常經典的多線程題目,題目大意如下:有一個寫者很多讀者,多個讀者可以同時讀文件,但寫者在寫文件時不允許有讀者在讀文件,同樣有讀者讀時寫者也不能寫。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章