日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OS- -线程详解

發(fā)布時間:2024/4/11 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OS- -线程详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

OS- -線程詳解

文章目錄

  • OS- -線程詳解
    • 一、線程
      • 1.線程的使用
        • 多線程解決方案
        • 單線程解決方案
        • 狀態(tài)機解決方案
      • 2.經(jīng)典的線程模型
        • 線程系統(tǒng)調(diào)用
      • 3.POSIX線程
      • 4.線程實現(xiàn)
        • 在用戶空間中實現(xiàn)線程
        • 在用戶空間實現(xiàn)線程的優(yōu)勢
        • 在用戶空間實現(xiàn)線程的劣勢
      • 5.在內(nèi)核中實現(xiàn)線程
      • 6.混合實現(xiàn)

一、線程

  • 在傳統(tǒng)的操作系統(tǒng)中,每個進程都有一個地址空間和一個控制線程。事實上,這是大部分進程的定義。
  • 不過,在許多情況下,經(jīng)常存在同一地址空間中運行多個控制線程的情形,這些線程就像是分離的進程。

下面我們就著重探討一下什么是線程

1.線程的使用

  • 或許這個疑問也是你的疑問,為什么要在進程的基礎上再創(chuàng)建一個線程的概念,準確的說,這其實是進程模型和線程模型的討論,回答這個問題,可能需要分三步來回答:
  • ?多線程之間會共享同一塊地址空間和所有可用數(shù)據(jù)的能力,這是進程所不具備的
  • ?線程要比進程更輕量級,由于線程更輕,所以它比進程更容易創(chuàng)建,也更容易撤銷。在許多系統(tǒng) 中,創(chuàng)建一個線程要比創(chuàng)建一個進程快10-100倍。
  • ?第三個原因可能是性能方面的探討,如果多個線程都是CPU密集型的,那么并不能獲得性能上的 增強,但是如果存在著大量的計算和大量的I/O處理,擁有多個線程能在這些活動中彼此重疊進 行,從而會加快應用程序的執(zhí)行速度

多線程解決方案

  • 現(xiàn)在考慮一個線程使用的例子:一個萬維網(wǎng)服務器,對頁面的請求發(fā)送給服務器,而所請求的頁面發(fā)送 回客戶端。

  • 在多數(shù)web站點上,某些頁面較其他頁面相比有更多的訪問。

  • 例如,索尼的主貞比任何一 個照相機詳情介紹頁面具有更多的訪問
  • Web服務器可以把獲得大量訪問的頁面集合保存在內(nèi)存中,避 免到磁盤去調(diào)入這些頁面,從而改善性能。
  • 這種頁面的集合稱為高速緩存(cache),高速緩存也應用 在許多場合中,比如說CPU緩存。

  • 上面是一個web服務器的組織方式,一個叫做 調(diào)度線程(dispatcher thread)的線程從網(wǎng)絡中讀 入工作請求,在調(diào)度線程檢查完請求后,它會選擇一個空閑的(阻塞的)工作線程來處理請求,通常是 將消息的指針寫入到每個線程關聯(lián)的特殊字中。
  • 然后調(diào)度線程會喚醒正在睡眠中的工作線程,把工作線 程的狀態(tài)從阻塞態(tài)變?yōu)榫途w態(tài)。
  • 當工作線程啟動后,它會檢查請求是否在web頁面的高速緩存中存在,這個高速緩存是所有線程都可 以訪問的。
  • 如果高速緩存不存在這個web頁面的話,它會調(diào)用一個read操作從磁盤中獲取頁面并且 阻塞線程直到磁盤操作完成。
  • 當線程阻塞在硬盤操作的期間,為了完成更多的工作,調(diào)度線程可能挑選 另一個線程運行,也可能把另一個當前就緒的工作線程投入運行。
  • 這種模型允許將服務器編寫為順序線程的集合,在分派線程的程序中包含一個死循環(huán),該循環(huán)用來獲得 工作請求并且把請求派給工作線程。
  • 每個工作線程的代碼包含一個從調(diào)度線程接收的請求,并且檢查 web高速緩存中是否存在所需頁面,如果有,直接把該頁面返回給客戶,接著工作線程阻塞,等待一個 新請求的到達。如果沒有,工作線程就從磁盤調(diào)入該頁面,將該頁面返回給客戶機,然后工作線程阻 塞,等待一個新請求。

下面是調(diào)度線程和工作線程的代碼,這里假設TRUE為常數(shù)1, buf和page分別是保存工作請求和 Web頁面的相應結構。

單線程解決方案

現(xiàn)在考慮沒有多線程的情況下,如何編寫Web服務器。

  • 我們很容易的就想象為單個線程了,Web服務 器的主循環(huán)獲取請求并檢查請求,并爭取在下一個請求之前完成工作。
  • 在等待磁盤操作時,服務器空 轉(zhuǎn),并且不處理任何到來的其他請求。結果會導致每秒中只有很少的請求被處理

所以這個例子能夠說 明多線程提高了程序的并行性并提高了程序的性能。

狀態(tài)機解決方案

到現(xiàn)在為止,我們已經(jīng)有了兩種解決方案,單線程解決方案和多線程解決方案,其實還有一種解決方案 就是狀態(tài)機解決方案,它的流程如下:

  • 如果目前只有一個非阻塞版本的read系統(tǒng)調(diào)用可以使用,那么當請求到達服務器時,這個唯一的read 調(diào)用的線程會進行檢查

  • 如果能夠從高速緩存中得到響應,那么直接返回,如果不能,則啟動一個非阻 塞的磁盤操作服務器在表中記錄當前請求的狀態(tài)

  • 然后進入并獲取下一個事件,緊接著下一個事件可能就是一個新工 作的請求或是磁盤對先前操作的回答。

  • 如果是新工作的請求,那么就開始處理請求。如果是磁盤的響 應,就從表中取出對應的狀態(tài)信息進行處理。

  • 對于非阻塞式磁盤I/O而言,這種響應一般都是信號中斷 響應。

  • 每次服務器從某個請求工作的狀態(tài)切換到另一個狀態(tài)時,都必須顯示的保存或者重新裝入相應的計算狀 態(tài)。

  • 這里,每個計算都有一個被保存的狀態(tài),存在一個會發(fā)生且使得相關狀態(tài)發(fā)生改變的事件集合,我 們把這類設計稱為有限狀態(tài)機(finite-state machine)

有限狀態(tài)機杯廣泛的應用在計算機科學 中。

  • 這三種解決方案各有各的特性,多線程使得順序進程的思想得以保留下來,并且實現(xiàn)了并行性,但是順 序進程會阻塞系統(tǒng)調(diào)用;
  • 單線程服務器保留了阻塞系統(tǒng)的簡易性,但是卻放棄了性能。有限狀態(tài)機的處 理方法運用了非阻塞調(diào)用和中斷,通過并行實現(xiàn)了高性能,但是給編程增加了困難。

2.經(jīng)典的線程模型

理解進程的另一個角度是,用某種方法把相關的資源集中在一起。

  • 進程有存放程序正文和數(shù)據(jù)以及其他 資源的地址空間。這些資源包括打開的文件、子進程、即將發(fā)生的定時器、信號處理程序、賬號信息等。把這些信息放在進程中會比較容易管理。
  • 另一個概念是,進程中擁有一個執(zhí)行的線程,通常簡寫為 線程(thread)。
  • 線程會有程序計數(shù)器,用 來記錄接著要執(zhí)行哪一條指令;線程還擁有寄存器,用來保存線程當前正在使用的變量;線程還會有堆 棧,用來記錄程序的執(zhí)行路徑
  • 盡管線程必須在某個進程中執(zhí)行,但是進程和線程完完全全是兩個不同 的概念,并且他們可以分開處理。
  • 進程用于把資源集中在一起,而線程則是CPU上調(diào)度執(zhí)行的實體。
  • 線程給進程模型增加了一項內(nèi)容,即在同一個進程中,允許彼此之間有較大的獨立性且互不干擾。
  • 在一 個進程中并行運行多個線程類似于在一臺計算機上運行多個進程。
  • 在多個線程中,各個線程共享同一地 址空間和其他資源。在多個進程中,進程共享物理內(nèi)存、磁盤、打印機和其他資源。
  • 因為線程會包含有 一些進程的屬性,所以線程被稱為輕量的進程(lightweight processes)
  • 多線程 (multithreading) 一詞還用于描述在同一進程中多個線程的情況。

下圖我們可以看到三個傳統(tǒng)的進程,每個進程有自己的地址空間和單個控制線程。

  • 每個線程都在不同的 地址空間中運行
  • 下圖中,我們可以看到有一個進程三個線程的情況。每個線程都在相同的地址空間中運行
  • 線程不像是進程那樣具備較強的獨立性。同一個進程中的所有線程都會有完全一樣的地址空間,這意味 著它們也共享同樣的全局變量。
  • 由于每個線程都可以訪問進程地址空間內(nèi)每個內(nèi)存地址,因此一個線程 可以讀取、寫入甚至擦除另一個線程的堆棧。

線程之間除了共享同一內(nèi)存空間外,還具有如下不同的內(nèi) 容

  • 上圖左邊的是同一個進程中每個線程共享的內(nèi)容,上圖右邊是每個線程中的內(nèi)容。也就是說左邊的列 表是進程的屬性,右邊的列表是線程的屬性。
  • 和進程一樣,線程可以處于下面這幾種狀態(tài):運行中、阻塞、就緒和終止(進程圖中沒有畫)。
  • 正在運 行的線程擁有CPU時間片并且狀態(tài)是運行中。一個被阻塞的線程會等待某個釋放它的事件。
  • 例如,當 一個線程執(zhí)行從鍵盤讀入數(shù)據(jù)的系統(tǒng)調(diào)用時,該線程就被阻塞直到有輸入為止。線程通常會被阻塞,直 到它等待某個外部事件的發(fā)生或者有其他線程來釋放它。線程之間的狀態(tài)轉(zhuǎn)換和進程之間的狀態(tài)轉(zhuǎn)換是 —樣的。

每個線程都會有自己的堆棧,如下圖所示:

線程系統(tǒng)調(diào)用

  • 進程通常會從當前的某個單線程開始,然后這個線程通過調(diào)用一個庫函數(shù)(比如thread.create ) 創(chuàng)建新的線程。
  • 線程創(chuàng)建的函數(shù)會要求指定新創(chuàng)建線程的名稱。創(chuàng)建的線程通常都返回一個線程標識 符,該標識符就是新線程的名字。
  • 當一個線程完成工作后,可以通過調(diào)用一個函數(shù)(比如thread_exit )來退出
  • 緊接著線程消失,狀 態(tài)變?yōu)榻K止,不能再進行調(diào)度。在某些線程的運行過程中,可以通過調(diào)用函數(shù)例如thread_join , 表示一個線程可以等待另一個線程退出
  • 這個過程阻塞調(diào)用線程直到等待特定的線程退出。在這種情況 下,線程的創(chuàng)建和終止非常類似于進程的創(chuàng)建和終止。
  • 另一個常見的線程是調(diào)用thread-yield ,它允許線程自動放棄CPU從而讓另一個線程運行。
  • 這樣 一個調(diào)用還是很重要的,因為不同于進程,線程是無法利用時鐘中斷強制讓線程讓出CPU的。

3.POSIX線程

為了使編寫可移植線程程序成為可能,IEEE在IEEE標準1003.1c中定義了線程標準。

線程包被定義 為Pthreads .大部分的UNIX系統(tǒng)支持它。這個標準定義了 60多種功能調(diào)用,一一列舉不太現(xiàn) 實,下面為你列舉了一些常用的系統(tǒng)調(diào)用。

  • POSIX線程(通常稱為pthreads)是一種獨立于語言而存在的執(zhí)行模型,以及并行執(zhí)行模型。
  • 它允許程序控制時間上重疊的多個不同的工作流程。每個工作流程都稱為一個線程,可以通過調(diào)用 POSIX ThreadsAPI來實現(xiàn)對這些流程的創(chuàng)建和控制。可以把它理解為線程的標準。
  • POSIX Threads的實現(xiàn)在許多類似且符合POSIX的操作系統(tǒng)上可用,例如FreeBSD、NetBSD、 OpenBSDs、Linux、macOS、Androids Solaris,它在現(xiàn)有 Windows API 之上實現(xiàn)了 pthreado
  • IEEE是世界上最大的技術專業(yè)組織,致力于為人類的利益而發(fā)展技術👏👏👏。

  • 所有的Pthreads都有特定的屬性,每一個都含有標識符、一組寄存器(包括程序計數(shù)器)和一組存儲 在結構中的屬性。這個屬性包括堆棧大小、調(diào)度參數(shù)以及其他線程需要的項目。
  • 新的線程會通過pthread.create創(chuàng)建,新創(chuàng)建的線程的標識符會作為函數(shù)值返回。這個調(diào)用非常像 是UNIX中的fork系統(tǒng)調(diào)用(除了參數(shù)之外),其中線程標識符起著PID的作用,這么做的目的 是為了和其他線程進行區(qū)分。
  • 當線程完成指派給他的工作后,會通過pthread.exit來終止。這個調(diào)用會停止線程并釋放堆棧。
  • 一般一個線程在繼續(xù)運行前需要等待另一個線程完成它的工作并退出。可以通過pthread.join線程 調(diào)用來等待別的特定線程的終止。而要等待線程的線程標識符作為一個參數(shù)給出。
  • 有時會出現(xiàn)這種情況:一個線程邏輯上沒有阻塞,但感覺上它已經(jīng)運行了足夠長的時間并且希望給另外 —個線程機會去運行。這時候可以通過pthread_yield來完成。

下面兩個線程調(diào)用是處理屬性的。

  • pthread-attr_init建立關聯(lián)一個線程的屬性結構并初始化成默 認值,這些值(例如優(yōu)先級)可以通過修改屬性結構的值來改變。
  • 最后,pthread_attr_destroy刪除一個線程的結構,釋放它占用的內(nèi)存。 它不會影響調(diào)用它的線 程,這些線程會一直存在。

為了更好的理解pthread是如何工作的,考慮下面這個例子:

  • 主線程在宣布它的指責之后,循環(huán)NUMBER_OF_THREADS次,每次創(chuàng)建一個新的線程。
  • 如果線程創(chuàng)建 失敗,會打印出一條信息后退出。在創(chuàng)建完成所有的工作后,主程序退出。

4.線程實現(xiàn)

  • 主要有三種實現(xiàn)方式

  • ?在用戶空間中實現(xiàn)線程;

  • ?在內(nèi)核空間中實現(xiàn)線程;

  • ?在用戶和內(nèi)核空間中混合實現(xiàn)線程。

下面我們分開討論一下

在用戶空間中實現(xiàn)線程

  • 第一種方法是把整個線程包放在用戶空間中,內(nèi)核對線程一無所知,它不知道線程的存在。

所有的這類 實現(xiàn)都有同樣的通用結構:

  • 線程在運行時系統(tǒng)之上運行,運行時系統(tǒng)是管理線程過程的集合,包括前面提到的四個過程: pthread_create,pthread_exit, pthreadjoin 和 pthread_yieldo
  • 運行時系統(tǒng)(Runtime System)也叫做運行時環(huán)境,該運行時系統(tǒng)提供了程序在其中運行的環(huán)境。
  • 此環(huán)境可能會解決許多問題,包括應用程序內(nèi)存的布局,程序如何訪問變量,在過程之間傳遞參數(shù)的機制,與操作系統(tǒng)的接口等等。
  • 編譯器根據(jù)特定的運行時系統(tǒng)進行假設以生成正確的代碼。
    通常,運行時系統(tǒng)將負責設置和管理堆棧,并且會包含諸如垃圾收集,線程或語言內(nèi)置的其 他動態(tài)的功能。
  • 在用戶空間管理線程時,每個進程需要有其專用的線程表(thread table),用來跟蹤該進程中的線 程。

  • 這些表和內(nèi)核中的進程表類似,不過它僅僅記錄各個線程的屬性,如每個線程的程序計數(shù)器、堆棧 指針、寄存器和狀態(tài)。

  • 該線程標由運行時系統(tǒng)統(tǒng)一管理。當一個線程轉(zhuǎn)換到就緒狀態(tài)或阻塞狀態(tài)時,在 該線程表中存放重新啟動該線程的所有信息,與內(nèi)核在進程表中存放的信息完全一樣。

在用戶空間實現(xiàn)線程的優(yōu)勢

  • 在用戶空間中實現(xiàn)線程要比在內(nèi)核空間中實現(xiàn)線程具有這些方面的優(yōu)勢:

  • 考慮如果在線程完成時或者是 在調(diào)用pthread_yield時,必要時會進程線程切換,然后線程的信息會被保存在運行時環(huán)境所提供 的線程表中,然后,線程調(diào)度程序來選擇另外一個需要運行的線程。

  • 保存線程的狀態(tài)和調(diào)度程序都是本 地過程,所以啟動他們比進行內(nèi)核調(diào)用效率更高。因而不需要切換到內(nèi)核,也就不需要上下文切換,也不需要對內(nèi)存高速緩存進行刷新,因為線程調(diào)度非常便捷,因此效率比較高。

  • 在用戶空間實現(xiàn)線程還有一個優(yōu)勢就是它允許每個進程有自己定制的調(diào)度算法。

  • 例如在某些應用程序 中,那些具有垃圾收集線程的應用程序(知道是誰了吧)就不用擔心自己線程會不會在不合適的時候停 止,這是一個優(yōu)勢。
  • 用戶線程還具有較好的可擴展性,因為內(nèi)核空間中的內(nèi)核線程需要一些表空間和堆 棧空間,如果內(nèi)核線程數(shù)量比較大,容易造成問題。

在用戶空間實現(xiàn)線程的劣勢

盡管在用戶空間實現(xiàn)線程會具有一定的性能優(yōu)勢,但是劣勢還是很明顯的,你如何實現(xiàn)阻塞系統(tǒng)調(diào)用 呢?

  • 假設在還沒有任何鍵盤輸入之前,一個線程讀取鍵盤,讓線程進行系統(tǒng)調(diào)用是不可能的,因為這會 停止所有的線程。
  • 所以,使用線程的一個目標是能夠讓線程進行阻塞調(diào)用,并且要避免被阻塞的線程影 響其他線程。
  • 與阻塞調(diào)用類似的問題是缺頁中斷問題,實際上,計算機并不會把所有的程序都一次性的放入內(nèi)存中,如果某個程序發(fā)生函數(shù)調(diào)用或者跳轉(zhuǎn)指令到了一條不在內(nèi)存的指令上,就會發(fā)生頁面故障,而操作系統(tǒng)將到磁盤上取回這個丟失的指令,這就稱為缺頁故障。
  • 而在對所需的指令進行讀入和執(zhí)行時,相 關的進程就會被阻塞。如果只有一個線程引起頁面故障,內(nèi)核由于甚至不知道有線程存在,通常會吧整個進程阻塞直到磁盤I/O完成為止,盡管其他的線程是可以運行的。
  • 另外一個問題是,如果一個線程開始運行,該線程所在進程中的其他線程都不能運行,除非第一個線程自愿的放棄CPU,在一個單進程內(nèi)部,沒有時鐘中斷,所以不可能使用輪轉(zhuǎn)調(diào)度的方式調(diào)度線程。除非其他線程能夠以自己的意愿進入運行時環(huán)境,否則調(diào)度程序沒有可以調(diào)度線程的機會。

5.在內(nèi)核中實現(xiàn)線程

  • 現(xiàn)在我們考慮使用內(nèi)核來實現(xiàn)線程的情況,此時不再需要運行時環(huán)境了。另外,每個進程中也沒有線程 表。

  • 相反,在內(nèi)核中會有用來記錄系統(tǒng)中所有線程的線程表。當某個線程希望創(chuàng)建一個新線程或撤銷一 個已有線程時,它會進行一個系統(tǒng)調(diào)用,這個系統(tǒng)調(diào)用通過對線程表的更新來完成線程創(chuàng)建或銷毀工 作。

  • 內(nèi)核中的線程表持有每個線程的寄存器、狀態(tài)和其他信息。這些信息和用戶空間中的線程信息相同,但是位置卻被放在了內(nèi)核中而不是用戶空間中。另外,內(nèi)核還維護了一張進程表用來跟蹤系統(tǒng)狀態(tài)。

  • 所有能夠阻塞的調(diào)用都會通過系統(tǒng)調(diào)用的方式來實現(xiàn),當一個線程阻塞時,內(nèi)核可以進行選擇,是運行在同一個進程中的另一個線程(如果有就緒線程的話)還是運行一個另一個進程中的線程。

  • 但是在用戶 實現(xiàn)中,運行時系統(tǒng)始終運行自己的線程,直到內(nèi)核剝奪它的CPU時間片(或者沒有可運行的線程存 在了)為止。

  • 由于在內(nèi)核中創(chuàng)建或者銷毀線程的開銷比較大,所以某些系統(tǒng)會采用可循環(huán)利用的方式來回收線程。

  • 當 某個線程被銷毀時,就把它標志為不可運行的狀態(tài),但是其內(nèi)部結構沒有受到影響。

  • 稍后,在必須創(chuàng)建 一個新線程時,就會重新啟用舊線程,把它標志為可用狀態(tài)。

  • 如果某個進程中的線程造成缺貞故障后,內(nèi)核很容易的就能檢查出來是否有其他可運行的線程,如果有的話,在等待所需要的頁面從磁盤讀入時,就選擇一個可運行的線程運行。這樣做的缺點是系統(tǒng)調(diào)用的代價比較大,所以如果線程的操作(創(chuàng)建、終止)比較多,就會帶來很大的開銷。

6.混合實現(xiàn)

結合用戶空間和內(nèi)核空間的優(yōu)點,設計人員采用了一種內(nèi)核級線程的方式,然后將用戶級線程與某些或者全部內(nèi)核線程多路復用起來:

  • 在這種模型中,編程人員可以自由控制用戶線程和內(nèi)核線程的數(shù)量,具有很大的靈活度。
  • 采用這種方 法,內(nèi)核只識別內(nèi)核級線程,并對其進行調(diào)度。其中一些內(nèi)核級線程會被多個用戶級線程多路復用。

總結

以上是生活随笔為你收集整理的OS- -线程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。