-
產生死鎖的四個必要條件
互斥條件:進程對所分配到的資源不允許其他進程進行訪問,若其他進程訪問該資源,只能等待,直至占有該資源的進程使用完成后釋放該資源
請求和保持條件:進程獲得一定的資源之后,又對其他資源發出請求,但是該資源可能被其他進程占有,此時請求阻塞,但又對自己獲得的資源保持不放
不可剝奪條件:是指進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完后自己釋放
環路等待條件:是指進程發生死鎖后,必然存在一個進程--資源之間的環形鏈
-
GCD線程死鎖產生的具體原因:在一個串行隊列的任務中,再向這個隊列同步添加任務。
典型例子:
image.png
我們分析一下:
image.png
主隊列main_queue是一個串行隊列,串行隊列的特點就是隊列中所有任務必須順序執行。也就是說必須按照添加到隊列中的先后順序執行。
我們再看一張圖:
image.png
我們在代碼中使用
dispatch_sync()
函數給主隊列添加了一個同步任務:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"線程死鎖");
});
}
也就是說后添加的同步任務5是在
viewDidLoad
任務2之后,只有等待任務2執行完之后才能執行任務5,這就是串行隊列的特點。但是任務5是一個同步任務,必須等任務5執行完才能執行其它任務,因此造成互相等待的死鎖。
再看一個例子
image.png
我們知道GCD分為同步任務和異步任務,最開始的例子是主線程的主隊列,相當于是一個同步任務。而這個例子證明了,即便是在異步任務只要任務隊列是串行隊列,在串行隊列的任務中再向隊列添加同步任務,就會造成死鎖,關鍵點不是同步還是異步,而是串行隊列。
總結
dispatch_sync()
函數會阻塞線程。當前隊列是串行隊列,任務必須順序執行。在串行隊列的任務A中給這個隊列添加同步任務B,相當于說這個串行隊列又多了一個任務B,任務B如果想要執行必須等待任務A執行完,但是任務B是同步任務,必須等任務B執行完才能執行其它任務,所以任務AB互相等待,造成死鎖。