1. 程式人生 > >LINUX 執行緒基礎, 執行緒同步,執行緒控制

LINUX 執行緒基礎, 執行緒同步,執行緒控制

一 執行緒基礎

   1)執行緒全稱控制執行緒
   2)多執行緒的優勢:
      a) 比程序方便,可以共享相同的記憶體空間及檔案描述符
      b) 可以用於多個任務,而這些任務如果用單程序來實現是序列,
         在多執行緒裡面由於CPU的排程可以實現穿插執行
      c) 用於互動程式,將使用者輸入輸出與其他部分分開,優化效能
   3)如何知道系統是否多執行緒pthread(POSIX執行緒)
      a) #ifdef  _POSIX_THREADS
      b) sysconf(_SC_THREADS)
   4)一個執行緒的資料結構
      執行緒ID,一組暫存器,棧,排程優先順序,訊號遮蔽字,errno,私有資料
      pthread_t 被實現為結構體這種才是可移植的
      但linux 直接這樣定義了 typedef unsigned long int pthread_t;
   5)執行緒id比較 pthread_equal(pthread_t ptd1, pthread_t ptd2)
     獲得執行緒ID pthread_self(void)
   6)執行緒建立 pthread_create(新執行緒的id,執行緒的屬性,執行緒執行地址,函式引數)
     ****新執行緒和主執行緒在建立後是競爭執行
     ****linux上是靠clone建立子程序來實現的,所以同一個程序裡面的執行緒獲取到pid可能不同(fedora8是相同的)
   7)執行緒終止
     如果任一執行緒呼叫了exit,_Exit,_exit,那麼整個程序就會終止
     a)從啟動函式返回
     b)被其他執行緒取消
     c)執行緒呼叫pthread_exit
   8)執行緒阻塞
     pthread_join(pthread_t aim_ptd) 阻塞當前執行緒一直到目標執行緒退出 類似於程序控制裡面的wait
     不能對分離狀態(設定為,或已經是detach狀態)的執行緒使用pthread_join,會返回失敗
     只有一個執行緒可以對某個執行緒使用pthread_join
   9)請求取消某個執行緒
     pthread_cancel
   10)登記執行緒退出清理函式,類似於atexit登記函式
      pthread_cleanup_push(函式指標,引數)
      除了pthread_exit,及響應取消請求而退出的時候執行清理函式,也可以呼叫pthread_cleanup_pop來執行函式
      執行緒return退出是不會執行清理函式的
      pthread_cleanup_pop(int execute) execute為0就不執行清理函式,只是刪除該處理函式,必須大於0才呼叫
   11)分離執行緒  pthread_detach
    pthread_t       tid;
    pthread_attr_t  attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&tid, &attr, THREAD_FUNCTION, arg);
    可以設定執行緒為預設的detach,好讓作業系統線上程結束的時候,回收預設的資源

二 執行緒同步

    原因: 現代計算機體系結構造成了資料不是順序一致來實現,  還有程式裡面的邏輯,不是原子操作而造成的
    
    1)互斥量  本質上就是多放一塊全域性條件變數
      pthread_mutex_t 訪問前加鎖,訪問完解鎖
      
      使用步驟:
      a)建立並初始化
        靜態的pthread_mutex_t 賦值常量 PTHREAD_MUTEX_INITIALIZER
        動態分配的pthread_mutext_t ,需要呼叫pthread_mutex_init初始化, pthread_mutex_destroy釋放
        通過pthread_mutex_init可以指定互斥量的屬性,預設屬性輸入引數null
      b)加鎖
        pthread_mutex_lock,如果已經有鎖則阻塞到互斥變數解鎖
        嘗試加鎖 pthread_mutex_trylock  加鎖不成功會馬上返回 EBUSY        
      c)訪問資料  
      d)解鎖   
        pthread_mutex_unlock 解鎖
        
    2)避免互斥量死鎖
       產生的原因: 執行緒對同一個互斥量加鎖2次,執行緒本身會陷入死鎖, 多個互斥量被多個執行緒以相反的順序訪問的時候
       
    3)讀寫鎖 又名 共享-獨佔鎖
      型別:     讀鎖 寫鎖
      資料型別: pthread_rwlock_t
      存在條件: 寫鎖一次最多一個執行緒佔據,讀鎖可以並行存在多個
      
      加鎖條件:
      a)當前鎖是寫鎖,所有其它新加鎖都會被阻塞
      b)當前鎖是讀鎖,如果新加鎖是讀鎖,那麼可以獲得訪問許可權
      c)當前鎖是讀鎖,如果新加鎖是寫鎖,那麼該鎖會被阻塞直到所有讀鎖解鎖。
      ****注意  為避免長期的讀鎖佔據寫的時間,但有寫鎖進來後,後續的讀鎖都會被拒絕掉
      ****適合讀的次數大於寫的次數的情況
      
      初始化及釋放:
      pthread_rwlock_init
      pthread_rwlock_destroy
      
      加鎖及解鎖
      pthread_rwlock_rdlock
      pthread_rwlock_wrlock
      pthread_rwlock_unlock  
      
      嘗試加鎖
      pthread_rwlock_tryrdlock
      pthread_rwlock_trywrlock
      
    4)條件變數
      資料型別 pthread_cond_t
      需要和互斥變數一起使用,受到互斥變數的保護
      靜態初始化 賦值常量 PTHREAD_COND_INITIALIZER
      動態初始化和釋放
      pthread_cond_init pthread_cond_destroy
      
      作用:
      給多個執行緒提供了一個會合的場所,允許執行緒以無競爭的方式等待特定的條件發生
      
      pthread_cond_wait  
        目的: 是通過互斥量的保護,講執行緒加入到某個等待條件的執行緒佇列裡面去
        過程:  進入函式前,對互斥量加鎖
                 函式內部,將執行緒加入到佇列並解鎖
                 函式返回,再次對互斥量加鎖
      pthread_cond_timedwait
          同上,但是有個時間等待限制,時間是絕對值,即具體的時刻,資料型別 timespec
      喚醒等待條件的執行緒:
      pthread_cond_signal 喚醒等待某個條件的一個執行緒
      pthread_cond_broadcast 喚醒等待某個條件的所有執行緒
     
      學習條件變數用法的2個例子
      http://www.cnblogs.com/yuallen/archive/2010/05/18/1738139.html
      http://www.cnblogs.com/hnrainll/archive/2011/05/01/2033903.html
      
      
 
三 執行緒控制
   
   1)執行緒屬性
     a)資料型別 pthread_attr_t
     b)初始化及釋放屬性結構 pthread_attr_init  pthread_attr_destroy
     c)獲取或設定執行緒分離狀態 pthread_attr_setdetachstate      pthread_attr_getdetachstate
       有2種可選的狀態值:
       PTHREAD_CREATE_DETACHED   分離狀態
       PTHREAD_CREATE_JOINABLE   正常狀態,可以使用pthread_join來獲取狀態
     d)應該獲取pthread_atr_destroy的返回值,因為使用pthread_attr_init初始化的時候可能分配有記憶體,如果釋放記憶體失敗的話,
       會造成記憶體洩漏
     e)控制執行緒棧的空間的大小
       需求:多個執行緒的棧空間累計超過了程序的可用虛擬地址空間
             執行緒呼叫函式的自動變數很多,或者遞迴很深
       1)管理stackaddr執行緒屬性,管理stacksize執行緒屬性
       pthread_attr_getstack
       pthread_attr_setstack  
       2)獲取或設定執行緒棧的大小
       pthread_attr_setstacksize  系統幫助分配記憶體,自己不用管
       pthread_attr_getstacksize
       3)執行緒棧的保護
       預設大小為巨集PAGESIZE,但修改了棧屬性後,這個值就會變成0
       pthread_attr_getguardsize
       pthread_attr_setguardsize
     f)執行緒屬性-併發度
       pthread_attr_setconcurency
       pthread_attr_getconcurency
     
   2)實現同步的3種方式中的物件的屬性
     a)互斥量屬性 pthread_mutexattr_t
       1)初始化及釋放  pthread_mutexattr_init pthread_mutexattr_destroy
       2)程序共享屬性
         獲取與設定共享屬性 pthread_mutexattr_getpshared   pthread_mutexattr_setpshared
         PTHREAD_PROCESS_PRIVAE 程序內的多個執行緒可以訪問同一個同步物件
         PTHREAD_PROCESS_SHARED 多個程序可以共享同一塊記憶體區域  記憶體共享技術
         
     b)互斥量型別屬性
         PTHREAD_MUTEX_NORMAL   標準的互斥量型別,不做錯誤檢查或死鎖檢查
         PTHREAD_MUTEX_DEFAULT  依賴於作業系統提供到其他型別的對映
         PTHREAD_MUTEX_ERRORCHECK 提供錯誤檢查
         PTHREAD_MUTEX_RECURSIVE 允許多次加鎖,但是需要解鎖對應次數 tmd,這個型別叫做遞迴鎖
         獲取與設定互斥量型別屬性
         pthread_mutexattr_gettype  pthread_mutexattr_settype
         
     c)讀寫鎖屬性 pthread_rwlockattr_t
        只支援程序共享屬性
     d)條件變數屬性pthread_condattr_t
        只支援程序共享屬性
        
        
 四 執行緒重入
     1)執行緒安全:如果一個函式同一時刻可以被多個執行緒安全地呼叫
     2)系統是否支援執行緒安全函式  sysconf(_POSIX_THREAD_SAFE_FUNCTIONS)
     3)非同步-訊號安全:如果函式對非同步訊號處理程式的重入是安全的
     4)鎖檔案的3個函式
       flockfile  ftrylockfile   funlockfile
       該鎖是遞迴鎖
     5)確保函式在程序裡面只被呼叫一次
       pthread_once_t var = PTHREAD_ONCE_INIT;
       pthread_once(&var, function);
 
 五 執行緒私有資料
     1)需要的資料型別: pthread_key_t
     2)建立私有資料的步驟
        pthread_key_t key;      
       a)pthread_key_create(&key, 清理函式地址) 一般通過pthread_once確保函式只被執行一次,變數只被初始化一次
       b)char* addr = pthread_getspecific(&key)
       c)為addr分配記憶體 malloc
       d)pthread_setspecific(&key, addr);
       e)pthread_key_delete刪除key
       f)執行緒退出,執行清理函式地址

 六 執行緒取消
     1)執行緒可以被設定為是否可取消
       pthread_setcancelstate(int state, int* oldstate)
     2)pthread_cancel只是一個申請,只有執行緒到達了取消點才會取消.
     3)延遲取消pthread_testcancel, 適合於沒有取消點的函式
     4)設定取消的型別pthread_setcanceltype
     
     
 七 執行緒與IO
     pread,pwrite 原子io操作
 八 執行緒與訊號
 
    每個執行緒有自己的訊號遮蔽字,但是他們共享  
    1)相同的訊號處理函式 2)該訊號與某函式的繫結,一個訊號繫結到某個函式,這個被所有執行緒共享, 他們只能看到一個
    多個執行緒公用程序的訊號遮蔽機制,除了2種情況以外:
    硬體故障的訊號與計時器超時的訊號,只遞送給某個執行緒,其它的訊號會發送給所有執行緒
    pthread_sigmask
    sigwait 等待訊號傳送.  一般操作需要先阻塞訊號,sigwait呼叫會取消訊號的阻塞狀態,直到新訊號到來
    pthread_kill
    sigwait(sigset_t*, int* signo)
    sigwait的引數2表示捕獲到的訊號值
    
    
 九 執行緒與fork
    pthread_atfork,理論內容相當多,過濾掉
    
    
 
 十   同一程序的所有執行緒共享同一個計時器
 十一 同一程序的所有執行緒共享相同的檔案描述符