一江春水向東流

          做一個有思想的人,期待與每一位熱愛思考的人交流,您的關注是對我最大的支持。

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            44 隨筆 :: 139 文章 :: 81 評論 :: 0 Trackbacks
          使用線程編寫程序需要技巧,而多線程的程序中的bug非常難以跟蹤、調試,因為這些bug經常是難以再現的。

          競爭條件

          當一個線程訪問一個數據結構的時候,另一個線程也訪問同一個數據結構,這時就出現了競爭條件——兩個線程(也可能是多個)競爭對同一個資源的訪問。
          當其中一個線程處理到一部分的時候,另外的線程可能進入了對同一數據的處理,而且出于調度的原因,它運行的比前一個更快;這時,同樣的處理可能就出現了多次。
          例如,一個代表任務列表的單向鏈表(隊列),一個線程從當前元素中讀出了下一個任務,并發現下一個任務不是空,準備將此一個任務置為NULL并執行任務;這時,調度使得這個線程停下來,另一個線程也從當前元素中讀出了下一個任務,當然下個任務仍然不是空值,這個線程也將要執行下一個任務。這樣,在某些不幸的情況下,這個任務被執行了兩次。
          更為不幸的情況下,執行任務的過程中線程被中斷,此時另一個線程釋放了任務的內存,那么執行中的線程會導致段錯誤。
          在比較“幸運”的情況下,這些事情可能從來也不發生;但是當程序運行在負荷很高的系統中時,這個bug就會凸現出來。

          互斥鎖
          為了排除競爭條件的影響,應該使一些操作變成“原子的”——這些操作既不能分割也不能中斷。
          當一個線程鎖定了互斥鎖后,其他線程也要求鎖定這個互斥鎖的時候,就會被阻塞;直到前面的線程解除鎖定后,其他線程才可以解除阻塞恢復運行。
          GNU/Linux保證線程在鎖定互斥鎖的過程中不會發生競爭條件,只有一個線程可以鎖定互斥鎖,其他線程的鎖定請求都會被阻塞。

          創建互斥鎖(Mutex),需要:
          `創建一個pthread_mutex_t類型的變量,將其指針傳入函數pthread_mutex_init中;該函數的第二個參數是指向一個mutex屬性對象(這個對象用來指定mutex的屬性)的指針。mutex對象只能初始化一次。
          `更簡單的辦法是,使用PTHREAD_MUTEX_INITIALIZER來獲得默認屬性的mutex對象:
          pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

          使用mutex:
          `調用pthread_mutex_lock函數,如果mutex對象未被鎖定,則此函數立即返回;如果已被鎖定,則此函數阻塞此線程的執行,直到mutex被解除鎖定。
          `每次解除鎖定后,只有一個線程可以解除阻塞恢復執行,其他調用線程都會繼續阻塞。選定的解除阻塞的線程是不可預知的。
          `調用pthread_mutex_unlock函數,可以解除調用線程對mutex對象的鎖定。在鎖定mutex的線程中,必須調用此函數以解除鎖定。

          mutex提供了解決競爭條件的方案,但是它帶來了一種新的bug——死鎖deadlock)。
          所謂死鎖,就是說一個線程在等待永遠不會發生的條件。
          一個簡單的死鎖:一個線程鎖定它自己已經鎖定的mutex。這時程序的表現依賴于mutex的類型:
          `快速排他鎖(fast mutex)——導致死鎖。
          `遞歸排他鎖(recursive mutex)——不導致死鎖。同一個線程可以安全的多次鎖定同一個已鎖定的mutex,但是鎖定的次數會被記錄下來,該線程還必須調用相應次數的pthread_mutex_unlock才能真正解除對mutex的鎖定。
          `檢錯排他鎖(error-checking mutex)——GNU/Linux視此操作為死鎖,但是對鎖定的mutex調用pthread_mutex_lock函數,函數立即返回錯誤碼EDEADLK。

          mutex的鎖定函數會阻塞,有時需要一個不阻塞就能知道mutex是否已鎖定的函數,以在發現mutex已鎖的情況下去完成其他工作并在以后再來檢查。這樣的函數是:
          pthread_mutex_trylock
          如果傳入的mutex已經被其他線程鎖定,那么這個函數返回錯誤碼EBUSY;如果未被鎖定,此函數會鎖定mutex,并返回0。這個函數不會阻塞。
          posted on 2008-02-15 10:15 allic 閱讀(1414) 評論(0)  編輯  收藏 所屬分類: C/C++
          主站蜘蛛池模板: 永定县| 九龙县| 丹巴县| 和林格尔县| 英山县| 德兴市| 永吉县| 长葛市| 无极县| 南城县| 汉川市| 澳门| 秦安县| 天门市| 精河县| 巴彦淖尔市| 安顺市| 丽江市| 新化县| 宾阳县| 郑州市| 襄城县| 克什克腾旗| 阳朔县| 登封市| 凉城县| 阳高县| 汶川县| 远安县| 肥乡县| 资阳市| 原平市| 重庆市| 松江区| 永顺县| 白银市| 手游| 恩施市| 连州市| 高台县| 达拉特旗|