二 Linux--多線程

線程的同步和互斥基本概念概述:現在操作系統基本都是多任務的操作系統,同時有大量可以調度的實體在運行 。在多任務操作系統當中 , 同時運行的多個任務可能:

  • 都需要訪問/使用同一種資源
  • 多個任務之間有依賴關系,某個任務的運行依賴于另一個任務
同步和互斥就是用來解決上述兩個問題的 。
同步和互斥的概念:
  • 互斥是要求兩個任務不能同時占用資源,會相互排序,必須等待一個線程運行完畢 , 另外一個線程才能過來使用資源 。
  • 同步是一種更為復雜的互斥,在互斥的基礎上,要求兩個任務的執行存在先后順序 。
其他相關概念:
  • 臨界資源: 多線程執行流共享的資源就叫做臨界資源
  • 臨界區: 每個線程內部,訪問臨界資源的代碼,就叫做臨界區
  • 原子性: 不會被任何調度機制打斷的操作,該操作只有兩態(無中間態,即使被打斷,也不會受影響),要么完成,要么未完成
互斥量mutex概念: 多個線程對一個共享變量進行操控時,會引發數據不一致的問題 。此時就引入了互斥量(也叫互斥鎖)的概念 , 來保證共享數據操作的完整性 。在被加鎖的任一時刻,臨界區的代碼只能被一個線程訪問 。
互斥鎖是一種簡單的加鎖的方法來控制對共享資源的訪問 , 互斥鎖只有兩種狀態,即加鎖(lock)和解鎖(unlock) 。
代碼的要求:
  • 代碼必須要有互斥行為:當代碼進入臨界區執行時,不允許其他線程進入該臨界區 。
  • 如果多個線程同時要求執行臨界區的代碼 , 并且臨界區沒有線程在執行,那么只能允許一個線程進入該臨界區 。
  • 如果線程不在臨界區中執行,那么該線程不能阻止其他線程進入臨界區 。

二 Linux--多線程

文章插圖
互斥量的接口互斥量其實就是一把鎖,是一個類型為pthread_mutex_t 的變量,使用前需要進行初始化操作,使用完之后需要對鎖資源進行釋放 。
  • 初始化互斥量
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);功能: 初始化一個互斥鎖參數: mutex:互斥鎖地址,類型是pthread_mutex_t attr:設置互斥量的屬性,通常可采取默認屬性,即可將attr改為NULL 可以使用宏pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER靜態初始化互斥鎖這種方法等價于使用NULL指定的attr參數調用pthread_mutex_init()來完成動態初始化,不同之處在于PTHREAD_MUTEX_INITIALIZER宏不進行錯誤檢查返回值: 成功:0 成功申請的鎖默認是打開的 失敗:非0 錯誤碼注意:restrict是C語言中的一種類型限定符,用于告訴編譯器,對象已經被指針引用,不能通過除該指針外所有其他直接或者間接的方式修改該對象的內容 。
  • 加鎖
int pthread_mutex_lock(pthread—mutex—t *mutex);功能: 對互斥鎖上鎖,若互斥鎖已經上鎖,則調用者阻塞,直到互斥鎖解鎖后再上鎖 。參數: mutex:互斥鎖地址 。返回值: 成功:0 失敗:非0錯誤碼int pthread_mutex_trylock(pthread_mutex_t *mutex);調用該函數時,若互斤鎖未加鎖 , 則上鎖,返回0;若互斥鎖已加鎖,則函數直接返回失敗 , 即EBUSY
  • 解鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex);功能: 對指定的互斥鎖解鎖參數: mutex:互斥鎖地址返回值: 成功:0 失?。悍?錯誤碼
  • 銷毀互斥量
int pthread_mutex_destroy(pthread_mdtex_t *mutex);功能: 銷毀指定的一個互斥鎖 ?;コ怄i在使用完畢后,必須要對互斥鎖進行銷毀 , 以釋放資源參數: mutex:互斥鎖地址返回值: 成功:0 失?。悍?錯誤碼注意:
  • 使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要銷毀
  • 不要銷毀一個已經加鎖的互斥量
  • 已經銷毀的互斥量,要確保后面不會有線程再嘗試加鎖
  • 加鎖的粒度要夠小
代碼示例:寫了一個搶票的小程序 , 用全局變量ticket代表現有票數,五個線程分別執行搶票的操作,也就是對ticket進行減減的操作,直到票數為0就停止搶票

推薦閱讀