本節書摘來自華章出版社《多核與gpu程式設計:工具、方法及實踐》一書中的第3章,第3.1節, 作 者 multicore and gpu programming: an integrated approach[阿聯酋]傑拉西莫斯·巴拉斯(gerassimos barlas) 著,張雲泉 賈海鵬 李士剛 袁良 等譯, 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
本章目标:
學習線程的定義以及建立方法。
學習完成特定任務的初始化線程方法。
學習多種終止多線程程式的技術。
了解多線程通路共享資料過程中的主要問題,例如競争和死鎖。
學習信号量和螢幕的定義和使用方法。
熟悉經典同步問題及其解決方法。
學習運作時動态管理線程。
學習多線程程式的調試技術。
從20世紀60年代麻省理工學院引入相容分時系統(ctss)以來,多個程式并發執行的現象已經變得較為常見。作業系統通過中斷目前正在執行的程式并将cpu的控制權交由另一個程式來完成這一功能。這種能有效地在多個程式間共享cpu時間(也即分時)的切換可以通過以下條件觸發:
時鐘或定時器的定期硬體中斷
不定期硬體中斷,例如某些裝置的請求
調用作業系統功能,例如執行輸入/輸出(i/o)操作
每個運作中的程式組成一個程序,亦即為了管理程式,一個包括代碼、資料、資源和執行狀态資訊的作業系統實體。
是以,每個程序值能在一個“時間片”内獲得cpu的控制權,然後将控制權交回作業系統,作業系統再将cpu交于另一個程序,以此類推。單cpu上的分時如圖3-1a所示。
分時這種方式可以提高計算資源的使用效率,但是它不能提高單個程序的運作速度,并且分時可能會由于減少配置設定給某個程序的時間片而直接降低程式性能,或者由于頻繁調用作業系統的任務排程程式的開銷而間接降低程式性能。
為了使程式獲得更多的計算時間(利用排程制導語句改變程式優先級),必須将其劃分為多個程序,在多核系統上也必須采取同樣的方法才能提高性能,此類示例如圖3-1b所示。最原始的生成(creating或者spawning)方法是調用fork函數,代碼清單3-1給出了一個示例。

生成一個程序需要精确複制目前程序的記憶體,包括所有代碼和資料,如圖3-2所示。在原始程式(父程序)和生成程式(子程序)間的唯一差別是子程序繼續執行fork語句的後的部分,亦即子程序沒有收到傳回值,是以子程序中的childid為0(見代碼清單3-1第13行)。邏輯上看,就像一個新的程序開始在此處執行,進而使得兩個程序執行不同任務(使兩個程序執行同樣的任務是無意義的)。
這種程序生成機制中一些顯而易見的問題包括:
為什麼複制代碼?它不應該在記憶體不可變區嗎?
子程序有父程序的所有資料的副本,那麼如何在兩個程序間交換資訊?
由于有些程式在運作時改變代碼,是以需要複制代碼。這也是病毒中的常見特征,但這并不是一個正常的程式行為。對于後一個問題,系統已經提供了多種解決該問題 的機制,但是最為簡單的還是通路一組共享變量。
由于fork函數中保留和複制程式映像的開銷,是以這種方法較為低效。幸運的是,還存在另一種通過線程來實作并發的方法,這将在下面進行介紹。