12.1 引言
*線程式控制制包括在同一進程中的多個線程之間如何保持資料的私人性,以及基於進程的系統調用如何與線程進行互動
12.2 線程限制
*線程限制的使用時為了增強應用程式在不同的作業系統實現之間的可移植性
12.3 線程屬性
*線程屬性guardsize控制著線程棧末尾之後用以避免棧溢出的擴充記憶體的大小
*線程的屬性還包括可取消狀態、可取消類型、並發度
*並發度控制著使用者級線程可以映射的核心線程或進程的數目
*如果作業系統的實現在核心級的線程和使用者級的線程之間保持一對一的映射,那麼改變並發度並不會有什麼效果,因為所有的使用者級的線程都可能被調度到
*如果作業系統的實現讓使用者級線程到核心級線程或進程之間的映射關係式多對一的話,那麼在給定時間內增加可啟動並執行使用者級線程數,肯呢過會改善效能
12.4 同步屬性
*互斥量屬性中兩個重要的屬性是進程共用屬性和類型屬性
*存在這樣的機制,允許相互獨立的多個進程把同一個記憶體區域對應到它們各自獨立的地址空間中。就像多個線程訪問共用資料一樣,多個進程訪問共用資料通常也需要同步。如果進程共用互斥量的屬性設定為PTHREAD_PROCESS_SHARED,從多個進程共用的記憶體地區中分配的互斥量就可以用於這些進程的同步
*PTHREAD_MUTEX_RECURSIVE互斥量類型允許同一線程在互斥量解鎖之前對該互斥量進行多次加鎖。用一個遞迴互斥量維護鎖的計數,在解鎖的次數和加鎖的次數不相同的情況下不會釋放鎖
*PTHREAD_MUTEX_DEFAULT類型可以用於請求預設語義
*不佔用時解鎖指的是一個線程對被另一個線程加鎖的互斥量進行解鎖的情況
*互斥量用於保護與條件變數關聯的條件
*如果需要把現有的單線程介面放到多線程環境中,遞迴互斥量是非常有用的
*為了保持介面與原來相同,可以把互斥量嵌入到資料結構中,把這個資料結構的地址作為參數引入。這種方案只有在為該資料結構提供了分配函數時才可行,所以應用並不知道資料結構的大小(假設在其中增加互斥量後必須擴大該資料結構的大小)
12.5 重入
*如果一個函數在同一時刻可以被多個安全執行緒地調用,就稱該函數時安全執行緒的
*很多函數並不是安全執行緒的,因為他們返回的資料是存放在靜態記憶體緩衝區中。通過修改介面,要求調用者自己提供緩衝區可以使函數變為安全執行緒的
*可以使用flockfile和ftrylockfile擷取與給定FILE對象關聯的鎖。這個鎖是遞迴的,當佔有這把鎖的時候,還可以再次擷取該鎖,這並不會導致死結
*雖然標準的I/O常式從它們各自的內部資料結構這一角度出發,可能是以安全執行緒的方式實現的,但有時把鎖開發給應用程式仍然是非常有用的。這允許應用程式把多個對標準I/O函數的調用組合成原子序列
12.6 線程私人資料
*線程私人資料(也稱線程特定資料)是儲存和查詢與某個線程相關的資料的一種機制
*除了建立鍵以外,pthread_key_create可以選擇為該鍵關聯解構函式,當線程退出時,如果資料地址以及被置為非null數值,那麼解構函式就會被調用,它唯一的參數就是該資料地址
*線程可以為線程私人資料分配多個鍵,每個鍵都可以有一個解構函式與它關聯
12.7 取消選項
*有兩個線程屬性並沒有包含在pthread_attr_t結構中,它們是可取消狀態和可取消類型
*pthread_setcancelstate把當前的可取消狀態設定為state,把原來的可取消狀態存放在由oldstate指向的記憶體單元中,這兩步是原子操作
*pthread_cancel調用並不等待線程終止,在預設情況下,線程在取消請求發出以後還是繼續運行,直到線程到達某個取消點。取消點是線程檢查是否被取消並按照請求進行動作的一個位置
*應用程式可以調用pthread_testcancel函數在程式中自己添加取消點。調用pthread_testcancel時,如果有某個取消請求正處於未決狀態,而且取消並沒有置為無效,那麼線程就會被取消。但是如果取消被置為無效時,pthread_testcancel調用就沒有任何效果
12.8 線程和訊號
*每個線程都有自己的訊號屏蔽字,但是訊號的處理時進程中所以線程共用的。這意味著儘管單個線程可以阻止某些訊號,但當線程修改了與某個訊號相關的處理行為以後,所以的線程都必須共用這個處理行為的改變。這樣如果一個線程選擇忽略某個訊號,而其他的線程可以恢複訊號的預設處理行為,或者為訊號設定一個新的處理常式,從而可以撤銷上述線程的訊號選擇
12.9 線程和fork
*用pthread_atfork函數最多可以安裝三個協助清理鎖的函數
*prepare fork處理常式由父進程在fork建立子進程前調用,這個fork處理常式的任務是擷取父進程定義的所有鎖
*parent fork處理常式是在fork建立了子進程以後,但在fork返回之前在父進程環境中調用的,這個fork處理常式的任務是對prepare fork處理常式所獲得的所以鎖進行解鎖
*child fork處理常式在fork返回之前在子進程環境中調用,與parent fork處理常式一樣,child fork處理常式也必須釋放prepare fork處理常式獲得的所有鎖
12.10 線程和I/O
*pread和pwrite函數將位移量的設定和資料的讀取/寫入組合為一個原子操作,可以解決並發線程對同一檔案進行讀寫操作的問題