麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統 > Unix > 正文

《Unix環境高級編程》讀書筆記 第11章-線程

2024-06-28 13:24:24
字體:
來源:轉載
供稿:網友
《Unix環境高級編程》讀書筆記 第11章-線程1. 引言
  • 了解如何使用多個控制線程在單進程環境中執行多個任務。
  • 不管在什么情況下,只要單個資源需要在多個用戶鍵共享,就必須處理一致性問題。
2. 線程概念
  • 典型的Unix進程可以看成只有一個控制線程:一個進程在某一時刻只能做一件事情。
  • 多線程帶來的好處:
    1. 通過為每種事件類型分配單獨的處理線程,可以簡化處理異步事件的代碼。每個線程在進行事件處理時可以采用同步編程模式。
    2. 多個進程必須使用操作系統提供的復制機制才能實現內存和文件描述符的共享。而多個線程自動地可以訪問相同的存儲空間和文件描述符。
    3. 有些問題可以分解從而提高整個程序的吞吐量。將原來串行化執行的任務變成交叉進行,當然,這些任務必須相互獨立、互不依賴。
    4. 交互的程序同樣可以通過使用多線程來改善響應時間,多線程可以把程序中處理用戶輸入輸出的部分與其他部分分開。
  • 處理器的數量并不影響程序結構,所以不管處理器的個數多少,程序都可以通過使用線程得以簡化。而且,即使多線程程序在串行化任務時不得不阻塞,在某些線程在阻塞的時候還有另外一些線程可以運行,所以多線程程序在單處理器上運行還是可以改善響應時間和吞吐量。
  • 我們討論的線程接口來自POSIX.1-2001,稱之為pthread。功能測試宏是_POSIX_THREADS,也可以使用_SC_THREADS常數調用sysconf函數。
3. 線程標識
  • 進程ID在整個系統中是唯一的。而線程ID只有在它所屬的進程上下文中才有意義。
  • 線程ID使用數據類型pthread_t表示,可以用一個結構來代表pthread_t,故須使用下面的函數來對兩個線程ID進行比較
#include <pthread.h>int pthread_equal(pthread_t tid1, pthread_t tid2); Returns: nonzero if equal, 0 otherwise
  • 通過pthread_self函數獲得自身的線程ID
#include <pthread.h>pthread_t pthread_self(void); Returns: the thread ID of the calling thread4. 線程創建
  • 在POSIX線程的情況下,程序開始運行時,它也是以單進程中的單個控制線程啟動的。在創建多個控制線程之前,程序的行為與傳統的進程并沒有什么區別。
  • 通過調用pthread_create函數創建新的線程
#include <pthread.h>int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg); Returns: 0 if OK, error number on failure
  • 新創建線程的線程ID會設置到tidp指向的內存單元中
  • atrr參數用于定制各種不同的線程屬性。直NULL時,創建一個具有默認屬性的線程
  • 新創建的線程從start_rtn函數的地址開始運行,該函數只有一個無類型指針參數arg。故如果需要向start_rtn函數傳遞的參數有一個以上,需要把這些參數放到一個結構中,傳遞該結構的地址
  • 線程創建時并不能保證哪個線程先運行:是新創建的線程,還是調用線程。
  • 新創建的線程可以訪問進程的地址空間,并且繼承調用線程的浮點環境和信號屏蔽字,但是該線程的掛起信號集會被清除,即被原線程阻塞之后收到的信號集不會被新線程繼承。
  • 注意:pthread函數在調用失敗時通常會返回錯誤碼,它們并不像其他的POSIX函數一樣設置errno。每個線程都提供errno的副本,這只是為了與使用errno的現有函數兼容。
5. 線程終止
  • 如果進程中的任意線程調用了exit、_Exit、_exit,那么整個進程就會終止
  • 如果默認的動作是終止進程,那么,發送到某個線程的信號就會終止整個進程
  • 單個線程可以通過3種方式退出,而不終止整個進程
    1. 線程可以簡單地從啟動例程中返回,返回值是線程的退出碼
    2. 線程可以被同一進程中的其他線程取消
    3. 線程調用pthread_exit
#include <pthread.h>void pthread_exit(void *rval_ptr);#include <pthread.h>int pthread_join(pthread_t thread, void **rval_ptr); Returns: 0 if OK, error number on failure
  • 進程中的其他進程可以通過調用pthread_join函數訪問到pthread_exit函數的指針參數rval_ptr
  • 調用線程將一直阻塞,直到指定的線程調用pthread_exit、從啟動例程中返回或者被取消。

    1. 如果線程從啟動例程中返回,rval_ptr包含返回碼
    2. 如果線程被取消,由rval_ptr指定的內存單元就設置為PTHREAD_CANCELED
    3. 如果線程調用pthread_exit,rval_ptr指向的內存單元作為返回值傳遞給調用pthread_join函數的其他線程
  • 線程可以通過調用pthread_cancel函數來請求取消同一進程中的其他線程

#include <pthread.h>int pthread_cancel(pthread_t tid); Returns: 0 if OK, error number on failure
  • 在默認情況下,pthread_cancel函數會使得由tid標識的線程的行為表現為如同調用了參數為PTHREAD_CANCELED的pthread_exit函數。但是,線程可以選擇忽略取消或控制如何被取消。
  • 注意:pthread_cancel并不等待線程終止,它僅僅提出請求。
#include <pthread.h>void pthread_cleanup_push(void (*rtn)(void *), void *arg);void pthread_cleanup_pop(int execute);
  • 線程可以安排它退出時需要調用的函數,類似于進程的atexit函數。這樣的函數稱為線程清理處理程序
  • 一個線程可以建立多個清理處理程序。處理程序記錄在棧中,執行順序與注冊順序相反。
  • 當線程執行以下動作時,由pthread_cleanup_push函數安排的清理函數rtn以單個參數arg被調用:
    1. 調用pthread_exit時
    2. 響應取消請求時
    3. 用非零execute參數調用pthread_cleanup_pop時(以0調用pthread_cleanup_pop函數時,清理函數不被調用)
  • 這些函數有一個限制,因其可以實現為宏,故必須在與現場相同的作用于中以匹配對的形式使用
  • 進程和線程原語的對比
  • 默認情況下,線程的終止狀態會保存直到對該線程調用pthread_join。如果線程已經被分離,線程的底層存儲資源可以在線程終止時立即被收回。在線程被分離后,不能用pthread_join函數等待它的終止狀態,調用該函數會產生未定義行為。
  • 可以調用函數pthread_detach分離線程
#include <pthread.h>int pthread_detach(pthread_t tid); Returns: 0 if OK, error number on failure
  • 可以通過修改傳給函數pthread_create的線程屬性,創建一個已處于分離狀態的線程。
6. 線程同步
  • 當多個控制線程共享相同的內存時,需要確保每個線程看到一致的數據視圖。故當一個線程可以修改的變量,其他線程也可以讀取或修改時,需要對這些線程進行同步,確保它們在訪問變量的存儲內容時不會訪問到無效的值。
  • 在變量修改時間多于一個存儲器訪問周期的處理器結構中,當存儲器讀與存儲器寫這兩個周期交叉時,這種不一致就會出現。

  • 兩個或多個線程試圖在同一時間修改同一變量時,也需要進行同步。考慮變量增量操作的情況:

  • 5個基本的同步機制:互斥量、讀寫鎖、條件變量、自旋鎖、屏障
6.1 互斥量
  • 互斥量從本質上說是一把鎖,在訪問共享資源前對互斥量進行加鎖,在訪問完成后釋放互斥量。
  • 只有將所有線程都設計成遵守相同數據訪問規則的,互斥機制才能正常工作。操作系統并不會為我們做數據訪問的串行化。如果允許其中某個線程在沒有得到鎖的情況下也可以訪問共享資源,那么即使其他的線程在使用共享資源前都申請鎖,也還是會出現數據不一致的問題。
  • 互斥變量使用數據類型pthread_mutex_t表示,使用互斥變量之前,必須對它進行初始化:
    1. 如果是靜態分配的互斥量,可以把它設置為常量PTHREAD_MUTEX_INITIALIZER
    2. 如果是動態分配(通過malloc函數)的互斥量,可以通過調用函數pthread_mutex_init進行初始化;在釋放內存前(通過free函數)需要調用pthread_mutex_destroy
#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);int pthread_mutex_destroy(pthread_mutex_t *mutex); Both return: 0 if OK, error number on failure
  • 要用默認的屬性初始化互斥量,只需把attr設為NULL
#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex); // 成功鎖住返回0;鎖住失敗返回EBUSY,不會阻塞int pthread_mutex_unlock(pthread_mutex_t *mutex); All return: 0 if OK, error number on failure6.2 避免死鎖
  • 如果線程試圖對同一個互斥量加鎖兩次,那么它自身就會陷入死鎖狀態。
  • 還有其他情況也會產生死鎖,如線程1先鎖住互斥量A,再鎖互斥量B;而線程2先鎖住互斥量B,再鎖住互斥量A。可以通過限制加鎖的順序避免。
  • 有時候,對互斥量的加鎖進行排序是很困難的。這種情況下,可以先釋放占有的鎖,然后過一段時間再試。
6.3 函數pthread_mutex_timedlock#include <pthread.h>#include <time.h>int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr); Returns: 0 if OK, error number on failure
  • 該函數允許綁定線程阻塞時間,超時后返回錯誤碼ETIMEDOUT
  • 指定愿意等待的絕對時間
6.4 讀寫鎖
  • 讀寫鎖允許更高的并行性
  • 讀寫鎖可以有3種狀態:讀模式下加鎖狀態、寫模式下加鎖狀態、不加鎖狀態。
  • 一次只有一個線程可以占有寫模式的讀寫鎖,但是多個線程可以同時占有讀模式的讀寫鎖

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 亚洲成人福利网站 | 最新在线黄色网址 | 国产精品av久久久久久网址 | 日韩视频在线观看免费视频 | 久久人人爽人人爽人人片av高请 | 久久久av亚洲男天堂 | 91免费高清视频 | 欧美成人se01短视频在线看 | 国产午夜精品一区 | 一区二区三区视频在线观看 | 成年人性视频 | 特级无码毛片免费视频尤物 | 国产精品久久久久久久久久尿 | 欧美亚洲国产日韩 | 国产精品视频导航 | 久久国产精品一区 | 日本在线不卡一区二区三区 | 在线一级片 | 黄色7777| 91久久99热青草国产 | 国产99久久久久久免费看 | 欧洲成人av | 激情网站视频 | 中文字幕爱爱视频 | 亚洲最大久久 | 97伦理 | 亚洲5区| 国产成人精品区 | 99精品视频一区二区 | 免费h片网站 | 97精品视频在线观看 | 中文字幕在线观看网址 | 成人精品久久久 | 久久影城 | av在线免费观看网 | 99在线精品视频免费观看20 | 精品在线视频观看 | 牛牛a级毛片在线播放 | 4480午夜 | 日韩av成人 | 狼伊千合综网中文 |