天天看點

.NET面試題系列[16] - 多線程概念(1) .NET面試題系列目錄

.NET面試題系列目錄

這篇文章主要是各個百科中的一些摘抄,簡述了程序和線程的來源,為什麼出現了程序和線程。

作業系統層面中程序和線程的實作

作業系統發展史

直到20世紀50年代中期,還沒出現作業系統,計算機工作采用手工操作方式。程式員将對應于程式和資料的已穿孔未的紙帶(或卡片)裝入輸入機,然後啟動輸入機把程式和資料輸入計算機記憶體,接着通過控制台開關啟動程式針對資料運作;計算完畢,列印機輸出計算結果;使用者取走結果并卸下紙帶(或卡片)後,才讓下一個使用者上機。

手工操作方式的兩個特點:

(1)使用者獨占全機。不會出現因資源已被其他使用者占用而等待的現象,但資源的使用率低。

(2)CPU等待手工操作。CPU的利用不充分。

20世紀50年代後期,出現人機沖突:手工操作的慢速度和計算機的高速度之間形成了尖銳沖突,手工操作方式已嚴重損害了系統資源的使用率(使資源使用率降為百分之幾,甚至更低),不能容忍。唯一的解決辦法:隻有擺脫人的手工操作,實作作業的自動過渡。這樣就出現了成批處理。

批處理系統(50年代後期)

批處理系統的追求目标是提高系統資源使用率和系統吞吐量,以及作業流程的自動化。批處理系統的一個重要缺點是不提供人機互動能力,給使用者使用計算機帶來不便。

批處理是指使用者将一批作業送出給作業系統後就不再幹預,由作業系統控制它們自動運作。這種采用批量處理作業技術的作業系統稱為批處理作業系統。批處理作業系統分為單道批處理系統和多道批處理系統。批處理作業系統不具有互動性,它是為了提高CPU的使用率而提出的一種作業系統。

早期的批處理系統屬于單道批處理系統,其目的是減少作業間轉換時的人工操作,進而減少CPU的等待時間。它的特征是記憶體中隻允許存放一個作業,即目前正在運作的作業才能駐留記憶體,作業的執行順序是先進先出,即按順序執行。

由于在單道批處理系統中,一個作業單獨進入記憶體并獨占系統資源,直到運作結束後下一個作業才能進入記憶體,當作業進行I/O操作時,CPU隻能處于等待狀态,是以,CPU使用率較低,尤其是對于I/O操作時間較長的作業。為了提高CPU的使用率,在單道批處理系統的基礎上引入了多道程式設計技術,這就形成了多道批處理系統,即在記憶體中可同時存在若幹道作業,作業執行的次序與進入記憶體的次序無嚴格的對應關系,因為這些作業是通過一定的作業排程算法來使用CPU的,一個作業在等待I/O處理時,CPU排程另外一個作業運作,是以CPU的使用率顯著地提高了。

批處理系統中,一個作業可以長時間地占用CPU。而分時系統中,一個作業隻能在一個時間片的時間内使用CPU。批處理系統不是嚴格意義上的作業系統。

多道程式設計與多道批處理系統(60年代中期)

多道程式技術(Multiprogramming)運作的特征:多道、宏觀上并行、微觀上串行。多道程式技術的提出是為了改善CPU的使用率。它需要硬體支援,并令CPU排程其他硬體工作。

  (1)多道:計算機記憶體中同時存放幾道互相獨立的程式(一開始稱為作業,後來演化為程序);

  (2)宏觀上并行:同時進入系統的幾道程式都處于運作過程中,即它們先後開始了各自的運作,但都未運作完畢;

  (3)微觀上串行:實際上,各道程式輪流地用CPU,并交替運作。

所謂多道程式設計指的是允許多個程式同時進入一個計算機系統的主存儲器并啟動進行計算的方法。也就是說,計算機記憶體中可以同時存放多道(兩個以上互相獨立的)程式,它們都處于開始和結束之間。從宏觀上看是并行的,多道程式都處于運作中,并且都沒有運作結束;從微觀上看是串行的,各道程式輪流使用CPU,交替執行。引入多道程式設計技術的根本目的是為了提高CPU的使用率,充分發揮計算機系統部件的并行性。現代計算機系統都采用了多道程式設計技術。

例如,如果一個程序有20%的時間使用CPU進行計算,另外80%的時間用來進行I/O,則在單道程式設計下CPU的使用率隻有20%,因為在I/O時間,CPU沒有事情做(隻有一個程序)。

如果是支援兩個程序的作業系統,即使用2道程式設計,則CPU隻在兩個程序同時進行I/O時才會處于閑置狀态,是以CPU使用率将會提高到:1-0.8*0.8=0.36=>36%。同理,如果同時運作更多的程序,CPU使用率會逐漸提高,直到某個臨界點為止。(PS:這裡的例子忽略了程序切換所需要的系統消耗)

雖然使用者獨占全機資源,并且直接控制程式的運作,可以随時了解程式運作情況,但這種工作方式因獨占全機造成資源效率極低。于是一種新的追求目标出現了:既能保證計算機效率,又能友善使用者使用計算機。20世紀60年代中期,計算機技術和軟體技術的發展使這種追求成為可能。

分時作業系統

分時作業系統是使一台計算機采用時間片輪轉的方式同時為幾個、幾十個甚至幾百個使用者服務的一種作業系統。

把計算機與許多終端使用者連接配接起來,分時作業系統将系統處理機時間與記憶體空間按一定的時間間隔,輪流地切換給各終端使用者的程式使用。由于時間間隔很短,每個使用者的感覺就像他獨占計算機一樣。分時作業系統的特點是可有效增加資源的使用率。

分時系統是當今計算機作業系統中最普遍使用的一類作業系統。實作多任務處理的方式有搶占式(Preemption)與協作式。協作式環境下,下一個程序被排程的前提是目前程序主動放棄時間片;搶占式環境下,作業系統完全決定程序排程方案,作業系統可以剝奪耗時長的程序的時間片,提供給其它程序。

程序(Process)

每個程式最終都會加載到記憶體中運作。多道程式設計的出現提供了程序的雛形 – 系統内部可以存放多于一個作業。分時作業系統中,系統内部也可以同時存在超過一個程式,這些同時存在于計算機記憶體中的程式就被稱為程序。但當我們在一個現代系統上運作一個程式時,會得到一個假象,就好像我們的程式是系統中目前運作着的唯一的程式。

程序的實作:通過作業系統的記憶體配置設定和排程。OS通過程序控制塊管理程序。通過虛拟記憶體實作程序隔離,一個程序無法通路其他程序正在占有的資源。但不安全的作業系統例如DOS,任何程序都可以通路其他程序的資源。

程序讓每個使用者感覺自己在獨占CPU。 

程序是多道程式設計自然而然的産物,而多道程式設計的目的則是為了提高計算機CPU的使用率(或者說系統的吞吐量)。

三個視角看程序模型

(1)實體視角:從實體記憶體的配置設定來看,每個程序占用一片記憶體空間,從這點上看,程序其實就是記憶體的某片空間。由于在任意時刻,一個CPU隻能執行一條指令,是以任意時刻在CPU上執行的程序隻有一個,而到底執行哪條指令是由實體程式計數器指定。是以,在實體層面,所有程序共用一個程式計數器,隻是CPU在不停地做程序切換。

(2)邏輯視角:從邏輯層面來看,每個程序都可以執行,也可以暫時挂起讓别的程序執行,之後又可以接着執行。是以,程序需要想辦法保持狀态才能在下次接着執行時從正确的地點(即上下文)開始。是以,每個程序都有自己的計數器,記錄其下一條指令所在的位置。(從邏輯上來說,程式計數器可以有多個)

(3)時序視角:從時間來看,每個程序都必須往前推進。在運作一定時間後,程序都應該完成了一定的工作量。換句話說,每次程序傳回,它都處在上次傳回點之後。

在現代作業系統中,程序管理和排程是作業系統的功能之一,特别是多任務處理的狀況下,這是必要的功能。作業系統将資源配置設定給各個程序,讓程序間可以分享與交換資訊,保護每個程序擁有的資源,不會被其他程序搶走,以及使程序間能夠同步(必要的話)。為了達到這些要求,作業系統為每個程序配置設定了一個資料結構,用來描述程序的狀态,以及程序擁有的資源。作業系統可以通過這個資料結構,來控制每個程序的運作。

如何實作程序

(1)實體基礎:程序的實體基礎是程式,程式又運作在計算機上,是以計算機上要運作程式首先要解決程序的存儲:給程序配置設定記憶體,使其安身立命。由于多個程序可能同時并存,是以需要考慮如何讓多個程序共享同一個實體記憶體而不發生沖突。OS通過記憶體管理(虛拟記憶體和程序隔離)來解決這個問題。

(2)程序切換:程序運作實際上是指程序在CPU上執行,那麼如何将CPU在多個程序之間進行切換也是一個問題。OS通過程序排程來解決這個問題。所謂程序排程,就是決定在什麼時候讓什麼程序來使用CPU,并在排程切換程序時,不會損失之前工作的資料。

虛拟記憶體和程序隔離

虛拟記憶體是計算機系統記憶體管理的一種技術。它使得應用程式認為它擁有連續的可用的記憶體(一個連續完整的位址空間),而實際上,它通常是被分隔成多個實體記憶體碎片,還有部分暫時存儲在外部磁盤存儲器上,在需要時進行資料交換。目前,大多數作業系統都使用了虛拟記憶體,如Windows家族的“虛拟記憶體”;Linux的“交換空間”等。

電腦中所運作的程式均需經由記憶體執行,若執行的程式占用記憶體很大或很多,則會導緻記憶體消耗殆盡。當記憶體耗盡時,Windows會用虛拟存儲器進行補償,它将計算機的RAM和硬碟上的臨時空間組合。當RAM運作速率緩慢時,它便将資料從RAM移動到稱為“分頁檔案”的空間中。将資料移入分頁檔案可釋放RAM,以便完成工作。一般而言,計算機的RAM容量越大,程式運作得越快。若計算機的速率由于RAM可用空間匮乏而減緩,則可嘗試通過增加虛拟記憶體來進行補償。但是,計算機從RAM讀取資料的速率要比從硬碟讀取資料的速率快,因而擴增RAM容量(可加記憶體條)是最佳選擇。

虛拟記憶體是Windows作為記憶體使用的一部分硬碟空間,在硬碟上其實就是一個碩大無比的檔案,檔案名是PageFile.sys,通常狀态下是看不到的。必須關閉資料總管對系統檔案的保護功能才能看到這個檔案。虛拟記憶體有時候也被稱為是“頁面檔案”就是從這個檔案的檔案名中來的。

程序隔離是為保護作業系統中程序互不幹擾而設計的一組不同硬體和軟體的技術。這個技術是為了避免程序A寫入程序B的情況發生。程序的隔離實作使用了虛拟記憶體。程序A的虛拟位址和程序B的虛拟位址不同,這樣就防止程序A将資料資訊寫入程序B。

程序隔離的安全性通過禁止程序間記憶體的通路可以友善實作。相比之下,一些不安全的作業系統(例如DOS)能夠允許任何程序對其他程序的記憶體進行寫操作。

程序排程(Process Scheduling)

在多程序的環境裡,雖然從概念上看,有多個程序在同時執行,但在單個CPU下,在任何時刻隻能有一個程序處于執行狀态,而其他程序則處于非執行狀态。那麼問題來了,我們是如何确定在任意時刻到底由哪個程序執行,哪些不執行呢?這就涉及到程序管理的一個重要組成部分:程序排程。

程序排程是作業系統程序管理的一個重要組成部分,其任務是選擇下一個要運作的程序。發生時鐘中斷是激發排程的其中一個可能。當排程結束,選擇下一個要運作的程序之後,如果選擇的程序不是現在正在運作的程序,CPU要進行上下文交換(Context Switching)。

我們必須解決如下問題:

  1. 使用某種排程算法安排多個程序順序執行
  2. 對于目前正在休息的程序,需要讓它在重新運作時,知道自己挂起之前的狀态。于是作為程序本身,它是沒有感覺自己被中斷過的,即上下文交換

基本排程算法

一般的程式任務分為三種:CPU計算密集型、IO密集型與平衡(計算與IO各半)型,對于不同類型的程式,排程需要達到的目的也有所不同。對于IO密集型,響應時間最重要;對于CPU密集型,則周轉時間最重要;而對于平衡型,進行某種響應和周轉之間的平衡就顯得比較重要。是以,程序排程的目标就是要達到極小化平均響應時間、極大化系統吞吐率、保持系統各個功能部件均處于繁忙狀态和提供某種貌似公平的機制。

先來先服務(FCFS)算法

先來先服務(FCFS)算法是一種最常見的算法,它是人的本性中的一種公平觀念。其優點就是簡單且實作容易,缺點則是短的工作有可能變得很慢,因為其前面有很長的工作在執行,這樣就會造成使用者的互動式體驗也比較差。例如排隊辦理業務時,你要辦理的業務隻需要幾分鐘就可以辦好,但是你前面的一個人辦理的事情很複雜需要1個小時,這時你需要在他後面等很久,于是你就想到:要是每個人輪流辦理10分鐘事務的話,那該多好!于是就出現了時間片輪轉算法。

時間片輪轉算法

時間片輪轉是對FCFS算法的一種改進,其主要目的是改善短程式的響應時間,實作方式就是周期性地進行程序切換。時間片輪轉的重點在于時間片的選擇,需要考慮多方因素:如果運作的程序多時,時間片就需要短一些;程序數量少時,時間片就可以适當長一些。是以,時間片的選擇是一個綜合的考慮,權衡各方利益,進行适當折中。

但是,時間片輪轉的系統響應時間也不一定總是比FCFS的響應時間短。時間片輪轉是一種大鍋飯的做法,但是現實生活中卻是走的“一部分人先富,先富帶動後富”的路線。例如,如果有30個任務,其中一個任務隻需要1秒時間執行,而其他29個任務需要30秒鐘執行,如果因為某種原因,這個隻要1秒鐘的任務排在另外29個任務的後面輪轉,則它需要等待29秒鐘才能執行(假定時間片為1秒)。于是,這個任務的響應時間和互動體驗就變得非常差。是以,短任務優先算法被提出。

短任務優先算法

短任務優先算法的核心是所有的任務并不都一樣,而是有優先級的區分。具體來說,就是短任務的優先級比長任務的高,而我們總是安排優先級高的任務先運作(這可能會導緻饑餓)。

短任務優先算法又分為兩種類型:一種是非搶占式,一種是搶占式。非搶占式當已經在CPU上運作的任務結束或阻塞時,從候選任務中選擇執行時間最短的程序來執行。而搶占式則是每增加一個新的程序就需要對所有程序(包括正在CPU上運作的程序)進行檢查,誰的時間短就運作誰。

由于短任務優先總是運作需要執行時間最短的程式,是以其系統平均響應時間在以上幾種算法中是最優的,這也是短任務優先算法的優點。但短任務優先算法也有缺點:一是可能造成長任務永遠無法得到CPU時間進而導緻“饑餓”。二是如何知道每個程序還需要運轉多久?于是為了解決第一個缺點,優先級排程算法被提出。而第二個缺點則可以采取一些啟發式的方法來進行估算,目前很多的人工智能算法都可以做這個事。

優先級排程算法

優先級排程算法給每個程序賦予一個優先級,每次需要程序切換時,找一個優先級最高的程序進行排程。這樣如果賦予長程序一個高優先級,則該程序就不會再“饑餓”。事實上,短任務優先算法本身就是一種優先級排程,隻不過它給予短程序更高的優先級而已。

該算法的優點在于可以賦予重要的程序以高優先級以確定重要任務能夠得到CPU時間,其缺點則有二:一是低優先級的程序可能會“饑餓”,二是響應時間無法保證。第一個缺點可以通過動态地調節任務的優先級解決,例如一個程序如果等待時間過長,其優先級将持續提升,超越其他程序的優先級,進而得到CPU時間。第二個缺點可以通過将一個程序優先級設定為最高來解決,但即使将優先級設定為最高,但如果每個人都将自己的程序優先級設定為最高,其響應時間還是無法保證。

混合排程算法

之前的算法都存在一定缺點,那麼可否有一個算法混合他們的優點,摒棄它們的缺點,這就是所謂的混合排程算法。混合排程算法将所有程序分為不同的大類,每個大類為一個優先級。如果兩個程序處于不同的大類,則處于高優先級大類的程序優先執行;如果處于同一個大類,采用時間片輪轉算法來執行。

程序狀态儲存

當發生上下文切換時,程序和CPU互動的資料(存儲在CPU的寄存器中)需要儲存。因為這些資料很快就會被另一個程序覆寫(通過和CPU的互動)。這些資料一般以名為程序控制塊(Process Control Block,PCB)的資料結構儲存起來。一般來說,這些資料應該包含:寄存器、程式計數器、狀态字、棧指針、優先級、程序ID、建立時間、所耗CPU時間、目前持有的各種句柄等等。

程序自己的資料是不需要儲存的,因為它儲存在記憶體中一塊固定的空間,而且程序隔離已經保證了這些資料是安全的。當程序恢複運作時,它隻需要再次回到屬于它的空間就可以找到上次所有的資料。

上下文切換(Context Switching)

   簡單的說,上下文切換就是當程序排程導緻要切換程序時,目前運作的程序将資料儲存進程序控制塊,然後通過排程算法選擇下一個程序,被選中的(目前在睡眠)的程序從程序控制塊中獲得自己之前工作的資訊,然後重新開始工作的過程。

   在三種情況下可能會發生上下文切換:中斷處理,多任務處理,使用者态切換。在中斷進行中,其他程式的行為打斷了目前正在運作的程式。當CPU接收到中斷請求時,會在正在運作的程式和發起中斷請求的程式之間進行一次上下文切換。在多任務進行中,CPU會在不同程式之間來回切換,每個程式都有相應的處理時間片,CPU在兩個時間片的間隔中進行上下文切換。使用者态切換則是使用者自己的行為,例如從遊戲中切出來,看一會網站的行為。

   上下文切換通常是計算密集型的。也就是說,它需要相當可觀的處理器時間,會對性能造成負面影響。相似的,線程也存在上下文切換。

程序間通信(Inter-Process Communication)

程序間通信(IPC,Inter-Process Communication),指至少兩個程序或線程間傳送資料或信号的一些技術或方法。每個程序都有自己的一部分獨立的系統資源,彼此是隔離的。為了能使不同的程序互相通路資源并進行協調工作,才有了程序間通信。舉一個典型的例子,使用程序間通信的兩個應用可以被分類為用戶端和伺服器,用戶端程序請求資料,服務端回複用戶端的資料請求。有一些應用本身既是伺服器又是用戶端,這在分布式計算中,時常可以見到。這些程序可以運作在同一計算機上或網絡連接配接的不同計算機上。

管道(Pipeline)

在類Unix作業系統(以及一些擴充例如Windows)中,管道(Pipeline)是原始的軟體管道:即是一個由标準輸入輸對外連結接起來的程序集合,是以每一個程序的輸出(stdout)被直接作為下一個程序的輸入(stdin)。管道所占的空間既可以是記憶體也可以是磁盤。

要建立一個管道,一個程序隻需要調用管道建立的系統調用(系統API)即可,該系統調用所做的事情就是在某種存儲媒體上劃出一片空間,賦給其中一個程序寫的權利,另一個程序讀的權利。

C#中類似的通信機制可以參考此文:http://www.cnblogs.com/yukaizhao/archive/2011/08/04/system-io-pipes.html

套接字(Socket)

套接字(Socket)的功能非常強大,可以支援不同層面、不同應用、跨網絡的通信。使用套接字進行通信需要雙方均建立一個套接字,其中一方作為伺服器方,另外一方作為客戶方。伺服器方必須首先建立一個服務區套接字,然後在該套接字上進行監聽,等待遠方的連接配接請求。客戶方也要建立一個套接字,然後向伺服器方發送連接配接請求。伺服器套接字在受到連接配接請求之後,将在伺服器方機器上建立一個客戶套接字,與遠方的客戶方套接字形成點到點的通信通道。之後,客戶方和伺服器友善可以直接通過類似于send和recv的指令在這個建立的套接字管道上進行交流了。

信号與信号量

信号類似于我們生活中的電報,如果你想給某人發一封電報,就拟好電文,然後将電文和收報人的資訊都交給電報公司。電報公司則将電報發送到收報人所在地的郵局,并通知收報人來取電報。其中,發封包時無需收報人事先知道,也無需進行任何協調。如果對方選擇不對信号做出響應,則将被OS終止運作。

在計算機中,信号就是一個核心對象或者是一個核心資料結構。發送方将該資料結構的内容填好,并指明該信号的目标程序後,發出特定的軟體中斷(這就是一個發電報的操作)。OS接收到特定的中斷請求後,知道是有程序要發送信号,于是到特定的核心資料結構裡查找信号接收方,并進行通知。接到通知的程序則對信号進行相應處理。

信号量來源于鐵路的運作:在一條單軌鐵路上,任何時候隻允許有一列火車行駛在該鐵路上,而管理這條鐵路的系統就是信号量。任何一列火車必須等到表明該鐵路可以行駛的信号後才能進入軌道。當列車進入後,需要将信号改為禁止狀态進入來防止别的列車同時進入。而當列車駛出單軌後,則需要将信号變回允許進入狀态,這很像以前的旗語。當然,通過聯想到我們實際開發中經常用的鎖,這就更容易了解了。

在計算機中,信号量實際上就是一個簡單整數。一個程序在信号變為0或1的情況下推進,并将信号變為1或0來防止别的程序同時推進。當該程序完成任務後,則将信号再改為0或1,進而允許其他程序執行。進而我們也可以看出,信号量已經不隻是一種通信機制,更是一種同步機制。

在系統中,給予每一個程序一個信号量,代表每個程序目前的狀态,未得到控制權的程序會在特定地方被強迫停下來,等待可以繼續進行的信号到來。如果信号量是一個任意的整數,通常被稱為計數信号量(Counting semaphore),或一般信号量(general semaphore);如果信号量隻有二進制的0或1,稱為二進制信号量(binary semaphore)。在linux系中,二進制信号量(binary semaphore)又稱Mutex。

計數信号量具備兩種操作動作,之前稱為V(又稱signal())與P(wait())。V操作會增加信号量S的數值,P操作會減少它。

運作方式:

  1. 初始化,給它一個非負數的整數值。
  2. 運作 P(wait()),信号量S的值将被減少。企圖進入臨界區塊的程序,需要先運作 P(wait())。當信号量S減為負值時,程序會被擋住,不能繼續;當信号量S不為負值時,程序可以獲準進入臨界區塊。(信号量通過這個機制,控制進入臨界區塊的程序的數量)
  3. 運作 V(又稱signal()),信号量S的值會被增加。結束離開臨界區塊的程序,将會運作 V(又稱signal())。當信号量S不為負值時,先前被擋住的其他程序,将可獲準進入臨界區塊。

C#對信号量的實作是Mutex和Semaphore。

共享記憶體

兩個程序共同擁有同一片記憶體。對于這片記憶體中的任何内容,二者均可以通路。要使用共享記憶體進行通信,程序A首先需要建立一片記憶體空間作為通信用,而其他程序B則将這片記憶體映射到自己的(虛拟)位址空間。這樣,程序A讀寫自己位址空間中對應共享記憶體的區域時,就是在和程序B進行通信。

消息隊列

消息隊列是一列具有頭和尾的消息排列,新來的消息放在隊列尾部,而讀取消息則從隊列頭部開始。

這樣看來,它和管道十分類似,一頭讀,一頭寫?的确,看起來很像管道,但又不是管道:

(1)消息隊列無固定的讀寫程序,任何程序都可以讀寫;而管道需要指定誰讀和誰寫;

(2)消息隊列可以同時支援多個程序,多個程序可以讀寫消息隊列;即所謂的多對多,而管道是點對點;

(3)消息隊列隻在記憶體中實作,而管道還可以在磁盤上實作;

線程

線程是CPU的一個虛拟。

微軟決定在一個程序中運作應用程式的每個執行個體。程序是應用程式要使用的資源的一個集合。當程式在程序中開始運作時,它就如同被關進了一個密閉的空間,裡面有所有它需要的東西。不同的密閉空間不會發生關系,任何一個程序死掉不會導緻整個系統崩潰。程序有自己的虛拟位址空間,確定這個程序使用的代碼不會被其他程序通路。并且當程序失去響應時,系統仍然可以工作,還可以用其他程序殺死失去響應的程序。

聽起來似乎沒問題?但雖然應用程式與作業系統之間已經透過程序來達到隔離和保護的效果,可是它們仍然有共享的資源:CPU。如果機器隻有一個CPU,那麼當某個應用程式進入無窮循環,那個唯一的CPU就會忙着跑無窮循環而無暇照顧其他應用程式,形同鎖住。于是,使用者會發現每個應用程式都無法響應了,無論滑鼠點在哪裡都不起作用。為了解決這個CPU無法分身的問題,線程(thread)便應運而生。

Windows通過線程來虛拟化CPU。線程使得每個程序(至少擁有一個線程)擁有CPU的一個“分身”(稱為邏輯CPU,真正的CPU稱為實體CPU)。當一個線程進入無限循環時,其他線程仍然可以繼續運作。

線程的好處如下:

1. 在很多現代的大型程式(例如Word)中,一個程式同時在做很多事情。當我們使用Microsoft Word時,實際上是打開了多個線程。這些線程一個負責顯示,一個負責接收輸入,一個定時進行存盤。這些線程一起運轉,讓我們感覺到輸入和顯示同時發生,而不用鍵入一些字元等待一會兒才顯示到螢幕上。在不經意間,Word還能定期自動儲存。這需要多個線程互相同步或互斥的并行完成工作,而将這些工作分解到不同的線程中去無疑簡化了程式設計模型。

2. 因為線程相比程序來說更加輕量,是以線程的建立和銷毀的代價更小。

3. 線程提高了性能,雖然線程宏觀上是并行的,但微觀上卻是串行(通過時間片)。從CPU角度線程無法提升性能,但如果某些線程涉及到等待資源(比如IO,等待輸入)時,多線程允許程序中的其它線程繼續執行而不是整個程序被阻塞,是以提高了CPU的使用率,從這個角度會提升性能(和多道程式設計相同)。

4. 在多CPU或多核的情況下,使用線程不僅僅在宏觀上并行,在微觀上也是并行的。

線上程模式下,一個程序至少有一個線程,也可以有多個線程。線程和程序既有相似又有不同之處。 

相似:

  1. 線程可以看成是輕量級的程序。是以使用了程序之後,再引入線程并不能提高性能。
  2. 不同的線程和不同的程序都可以通信。
  3. 線程和程序都有優先級,都需要系統進行排程。
  4. 線程和程序都有狀态。 

不同之處:

  1. 線程的任務是虛拟化CPU,令CPU不再是所有程序共享的一個互斥元件,程序的任務則是提高CPU的使用效率。
  2. 線程作為排程和分派的基本機關,而程序作為資源擁有的基本機關。同一程序中,線程的切換不會引起程序的切換,但從一個程序中的線程切換到另外一個程序中的線程時,将會引起程序切換。
  3. 一個程序可以包括多個線程,而且至少要有一個前台線程。
  4. 程序之間通過虛拟記憶體隔離,但一個程序中的線程共享所有程序的資源。

同程序一樣,線程也需要排程,通信和同步。

參考資料

http://www.cnblogs.com/edisonchou/p/5022508.html

https://zh.wikipedia.org/wiki/%E8%A1%8C%E7%A8%8B%E9%96%93%E9%80%9A%E8%A8%8A

http://www.cnblogs.com/edisonchou/p/5037403.html

http://www.cnblogs.com/CareySon/archive/2012/05/04/ProcessAndThread.html

百度百科