死鎖
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很多,這裡僅介紹本文用到的。
- 系統標準提供的兩個佇列
// 全域性佇列,也是一個並行佇列
dispatch_get_global_queue
// 主佇列,在主執行緒中執行,因為主執行緒只有一個,所以這是一個序列佇列
dispatch_get_main_queue
複製程式碼
- 除此之外,還可以自己生成佇列
// 從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)) // 非同步執行緒
複製程式碼