GCD 死鎖原因

未名小菜發表於2018-10-24

死鎖

1、定義:

所謂死鎖,通常指有兩個執行緒T1和T2都卡住了,並等待對方完成某些操作。T1不能完成是因為它在等待T2完成。但T2也不能完成,因為它在等待T1完成。於是大家都完不成,就導致了死鎖(DeadLock)。

2、產生死鎖的條件:

產生死鎖的四個必要條件:
(1) 互斥條件:一個資源每次只能被一個程式使用。
(2) 請求與保持條件:一個程式因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:程式已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 迴圈等待條件:若干程式之間形成一種頭尾相接的迴圈等待資源關係。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖 。

基本概念

1、同步&非同步

1.1、同步


同步執行:比如這裡的dispatch_sync,這個函式會把一個block加入到
指定的佇列中,而且會一直等到執行完blcok,這個函式才返回。因此在
block執行完之前,呼叫dispatch_sync方法的執行緒是阻塞的。
複製程式碼

1.2、非同步

非同步執行:一般使用dispatch_async,這個函式也會把一個block加入到
指定的佇列中,但是和同步執行不同的是,這個函式把block加入佇列後
不等block的執行就立刻返回了。
複製程式碼

1.3、關於這GCD兩個函式的強調:

dispatch_async 和 dispatch_sync 他們的作用是將 任務(block)新增進指定的佇列中。並根據是否為sync決定呼叫該函式的執行緒是否需要阻塞。
注意:這裡呼叫該函式的執行緒並不執行 引數中指定的任務(block塊),任務的執行者是GCD分配給任務所在佇列的執行緒。
結論:呼叫dispatch_sync和dispatch_async的執行緒,並不一定是任務(block塊)的執行者。
複製程式碼

2、序列&併發(佇列)

2.1、序列佇列

序列佇列:比如這裡的dispatch_get_main_queue。這個佇列中所有任務,一定按照FIFO(先來後到的順序)執行。
不僅如此,還可以保證在執行某個任務時,在它前面進入佇列的所有任務肯定執行完了。
對於每一個不同的序列佇列,系統會為這個佇列建立唯一的執行緒來執行程式碼。
複製程式碼

2.2、併發佇列

比如使用dispatch_get_global_queue。這個佇列中的任務也是按照FIFO(先來後到的順序)開始執行,注意是開始,但是它們的執行結束時間是不確定的,取決於每個任務的耗時。
併發佇列中的任務:GCD會動態分配多條執行緒來執行。具體幾條執行緒取決於當前記憶體使用狀況,執行緒池中執行緒數等因素。
複製程式碼

GCD API很多,這裡僅介紹本文用到的。

  1. 系統標準提供的兩個佇列
// 全域性佇列,也是一個並行佇列
dispatch_get_global_queue 
// 主佇列,在主執行緒中執行,因為主執行緒只有一個,所以這是一個序列佇列
dispatch_get_main_queue 
複製程式碼
  1. 除此之外,還可以自己生成佇列
// 從DISPATCH_QUEUE_SERIAL看出,這是序列佇列
dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL) 
// 同理,這是一個並行佇列
dispatch_queue_create("com.demo.concurrentQueue", DISPATCH_QUEUE_CONCURRENT) 
複製程式碼

接下來是同步與非同步執行緒的建立:

dispatch_sync(..., ^(block)) // 同步執行緒
dispatch_async(..., ^(block)) // 非同步執行緒
複製程式碼

相關文章