2011-08-01 139 views
2

我正在從一個應用程序接收來自HTTP連接的數據,並且數據由一個或多個線程進行處理。我使用NSCondition來允許讀者線程等待傳入數據,並且擁有連接線程在數據可用時廣播它們,但是我一直處於死鎖狀態,我看不出爲什麼。我要麼誤解NSCondition是如何工作的,要麼我長期以來一直盯着它看,我錯過了其他的東西。下面的代碼:NSCondition死鎖

// lock = NSCondition ivar 
// position = long long ivar 
// writeDataToFile performs no locking but just writes the data to an NSHandle and logs in debug 

- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { 
    [condition lock]; 
    @try { 
     [self writeDataToFile:data]; 
     position += [data length]; 
     hasMoreData = YES; 
    } @finally { 
     [condition broadcast]; 
     [condition unlock]; 
    } 
} 

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { 

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; 
    int statusCode = [httpResponse statusCode]; 
    requestSuccess = (statusCode == 200); 

    [condition lock]; 
    [condition broadcast]; 
    [condition unlock]; 
} 

- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { 
    [condition lock]; 
    hasMoreData = YES; 
    [condition broadcast]; 
    [condition unlock]; 
} 

- (void)waitForData { 
    [condition lock]; 
    @try { 
     while(!hasMoreData) { 
      [condition wait]; 
     } 
    } @finally { 
     hasMoreData = NO; 
     [condition unlock]; 
    } 
} 

現在這一般工作,但偶爾我看到應用程序掛起和樣品展示一個線程等待條件,另一個等待waitForData獲得鎖和其他等待獲取鎖`連接:didReceiveData」。

我的理解是,[condition wait]調用原子地解鎖它的內部互斥並等待條件,因此多個等待線程不應阻止線程獲取和廣播條件。

我錯過了什麼?

謝謝, Ĵ

回答

0

猜測,使用此方法

- (void)connection:(NSURLConnection *)connection 
    didFailWithError:(NSError *)error 

並且在該解鎖的條件。當您沒有得到響應時,[condition unlock];

此行不在調用。所以這些被鎖定,你的應用程序掛起,所以試圖使用這個建議。

+0

感謝您的建議,但我解鎖失敗方法中的條件(問題已更新,包括代碼)。我沒有包含它,因爲在這種情況下,由於線程懸掛在連接中,連接不會失敗:didReceiveData:selector。 – JWood

0

在一天結束時,我認爲使用鎖是一個複雜的解決方案。在主線程上使用同步IO是一個很大的禁忌,但是在後臺線程上執行它同樣可以,並且更容易處理異步請求。

所以,如果你在後臺線程上阻塞當前線程等待IO線程的整個混亂只是一個痛苦的屁股。替換爲+[NSURLConnection sendSynchronousRequest:returningResponse:error:]並完成它。

+0

感謝您的信息,但我實際上使用NSCondition,而不是NSConditionLock - http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSCondition_class/Reference/Reference.html – JWood

+0

我的壞。我仍然相信使用任何形式的鎖都是最後的選擇。 'NSURLConnection'已經有了一個非常好的超級測試實現來阻止IO;如果你已經在後臺線程中使用它。所以我更新我的答案以反映這一點。 – PeyloW

+0

由於應用程序的複雜性,非正式的鎖定確實是必要的,因爲多個線程可能在下載過程中從文件數據中的多個位置讀取。設置布爾值時,問題實際上歸結爲競爭條件。我已經在布爾實現了一個「雙鎖」,現在它工作正常。 – JWood