不管Java,C++都有程序、線程相關的内容。在這裡統一整理吧。
Python的線程,其實是僞線程,不能真正的并發。下面也有講。
線程自己基本上不擁有系統資源,隻擁有一點在運作中必不可少的資源(如程式計數器,一組寄存器和棧)。
多個線程共享記憶體。
程序:程序是程式的一次執行過程,是系統進行資源配置設定和排程的一個獨立機關。
程序實體(程序映像):由程式段、相關資料段和PCB三部分構成。程序是動态的,程序實體是靜态的。
PCB(程序控制塊):系統利用PCB來描述程序的基本情況和運作狀态,進而控制和管理程序;所謂建立程序,實際上是建立程序映像中的PCB;PCB是程序存在的唯一标志。
程序有5種狀态,其中前3種是基本狀态:
運作态、就緒态、阻塞态(等待态)。另兩種是建立态和終止态。
(1)配置設定ID與PCB:為新程序配置設定一個唯一的程序辨別号,并申請一個空白的PCB(PCB是有限的)。若PCB申請失敗則建立失敗。
(2)配置設定資源:為新程序的程式和資料、以及使用者棧配置設定必要的記憶體空間(在PCB 中展現)。注意:這裡如果資源不足(比如記憶體空間),并不是建立失敗,而是處于阻塞态。
(3)初始化PCB:主要初始化(1)标志資訊(2)處理機狀态資訊(3)處理機控制資訊,以及(4)設定程序的優先級等。
(4)排程:如果程序就緒隊列能夠接納新程序,就将新程序插入到就緒隊列,等待被排程運作。
注意,程序的建立是一個原子操作,執行期間不允許中斷,它是一個不可分割的基本機關。
引起程序終止的事件主要有:
(1)正常結束
(2)異常結束:如存儲區越界、非法指令、I/O故障等
(3)外界幹預:如操作員或作業系統幹預、父程序請求、父程序終止。
作業系統終止程序的過程如下:
(1)根據被終止程序的ID,檢索PCB,從中讀出該程序的狀态
(2)若被終止程序處于執行狀态,立即終止該程序的執行,将處理機資源配置設定給其他程序
(3)若該程序還有子程序,則應将其所有的子程序終止
(4)将該程序所擁有的資源,或歸還給其父程序或歸還給作業系統
(5)将該PCB從所在隊列(連結清單)中删除。
(1)儲存處理機上下文,包括程式計數器和其他寄存器。
(2)更新PCB資訊。
(3)把程序的PCB移入相應的隊列,如就緒、在某事件阻塞等隊列。
(4)選擇另一個程序執行,并更新其PCB。
(5)更新記憶體管理的資料結構。
(6)恢複處理機上下文。
注意:“排程”和“切換”的差別:排程是指決定資源配置設定給哪個程序的行為,是一種決策行為;切換是指實際配置設定的行為,是執行行為。一般來說,等有資源的排程,再有程序的切換。
線程是輕量化的程序,是程式執行流的最小機關;由線程ID、程式計數器、寄存器集合和堆棧組成;線程自己不擁有系統資源,隻擁有一點在運作中必不可少的資源,但它可與同屬一個程序的其他線程共享程序所擁有的全部資源。
(1)一個程式至少有一個程序,一個程序至少有一個線程。線程(Thread)是程序的一個實體,是CPU排程和分派的基本機關;
(2)程序擁有獨立的記憶體單元,而多個線程共享記憶體。進而線程效率更高;
(3)程序有獨立的位址空間,一個程序崩潰後,在保護模式下不會對其它程序産生影響,而線程沒有單獨的位址空間,一個線程死掉就等于整個程序死掉,是以多程序的程式要比多線程的程式健壯;
(4)程序切換時,耗費資源較大,效率要差一些;
(5)程序是系統資源配置設定的基本機關,線程是排程的基本機關。
線程獨有的内容:
線程上下文,包括線程ID、棧、棧指針、PC(程式計數器)、通用目的寄存器、條件碼。
線程共享的内容:
檔案描述符和整個使用者虛拟位址空間,包括隻讀文本(代碼)、靜态變量、堆、所有的共享庫代碼和資料區域組成。
(1)易于排程。
(2)提高并發性。通過線程可友善有效地實作并發性。程序可建立多個線程來執行同一程式的不同部分。
(3)開銷少。建立線程比建立程序要快,所需開銷很少。。
(4)利于充分發揮多處理器的功能。
(1)線程之間的同步和加鎖控制比較麻煩
(2)一個線程的崩潰影響到整個程式的穩定性
(3)線程多了之後,線程本身的排程也是一個麻煩事兒,需要消耗較多的CPU
線程可以是可結合的,或者是可分離的;
可結合的線程能夠被其他線程收回其資源和殺死。在被其他線程回收之前,它的存儲器資源(例如棧)是沒有被釋放的,相反一個分離的線程是不能被其他線程回收或殺死的。它的存儲器資源在它終止時由系統自動釋放;
為避免存儲器洩漏,每個可結合線程都應該被其他線程顯式地收回,要麼通過調用pthread_detach函數被分離;(對應于Java就是 Thread.join和Thread.detach )
預設情況下,線程被建立成可結合的。(注意:可結合是一種狀态,要調用join方法來進行結合/釋放)
來一個例子:
<a></a>
列印結果:
三個線程,同時sleep了5秒鐘,然後整個程式才結束。
如果synchronized加在函數上,那麼是每個線程分别sleep 5秒鐘,一共sleep 15秒鐘。
(1)管道:半雙工;用于父子、兄弟之間。
(2)命名管道(FIFO)
(2)消息隊列:消息連結清單存于核心,每個消息隊列由消息隊列辨別符辨別;于管道不同的是,消息隊列存放在核心中,隻有在核心重新開機時才能删除一個消息隊列;消息隊列的大小受限制。
(3)信号量(semophore):常用來處理臨界資源的通路同步問題。臨界資源:為某一時刻隻能由一個程序或線程操作的資源。
(4)共享記憶體:可以說是最有用的程序間通信方式,也是最快的IPC形式。
(5)套接字:也可用于不同機器之間。
(6)信号(Signal)
(1)臨界區:當多個線程通路一個獨占性共享資源時,可以使用臨界區對象。擁有臨界區的線程可以通路被保護起來的資源或代碼段,其他線程若想通路,則被挂起,直到擁有臨界區的線程放棄臨界區為止。
(注:Java的synchronized代碼段,也勉強可以算作臨界區,隻是語言标記互斥的實作方式;要通路代碼段,需要獲得傳給synchronized的Object這個對象的鎖。注意,每個java對象都隐含有一把鎖。
Java GC需要的safe point,為了讓多個線程都停下來,标記的區域-其他線程不進來,裡面的線程出來了,就開始GC- 跟臨界區的思想也有一點像)
(2)互斥量-mutex:互斥對象和臨界區對象非常相似,隻是其允許在程序間使用,而臨界區隻限制與同一程序的各個線程之間使用。
(3)條件變量:一個線程被挂起,直到某件事件發生。
(4)信号量:當需要一個計數器來限制可以使用某共享資源的線程數目時,可以使用“信号量”對象。CSemaphore類對象儲存了對目前通路某一個指定資源的線程的計數值,該計數值是目前還可以使用該資源的線程數目。如果這個計數達到了零,則所有對這個CSemaphore類對象所控制的資源的通路嘗試都被放入到一個隊列中等待,直到逾時或計數值不為零為止。
(5)事件:允許一個線程在處理完一個任務後,主動喚醒另外一個線程執行任務。
(6)套接字
本文轉自 jiu~ 部落格園部落格,原文連結:http://www.cnblogs.com/jiu0821/p/8628160.html,如需轉載請自行聯系原作者