2011-02-15 28 views
0

我有3個線程(除了主線程)。線程讀取,處理和寫入。他們每個人都會對一些緩衝區執行此操作,這些緩衝區會循環使用並重新使用。它以這種方式設置的原因是程序可以在其中一個正在運行時繼續執行其他任務。因此,例如,當程序寫入磁盤時,它可以同時讀取更多數據。使用NSConditionLock同步3個線程共享緩衝區。這很難

問題是我需要同步所有這些,以便處理線程不會嘗試處理尚未填充新數據的緩衝區。否則,處理步驟可能會處理其中一個緩衝區中的剩餘數據。

讀取線程將數據讀入緩衝區,然後將緩衝區標記爲數組中的「新數據」。因此,它的工作原理是這樣的:

//set up in main thread 
NSConditionLock *readlock = [[NSConditionLock alloc] initWithCondition:0]; 

//set up lock in thread 
[readlock lockWhenCondition:buffer_new[current_buf]]; 

//copy data to buffer 
memcpy(buffer[current_buf],source_data,data_length); 

//mark buffer as new (this is reset to 0 once the data is processed) 
buffer_new[current_buf] = 1; 

//unlock 
[readlock unlockWithCondition:0]; 

我用buffer_new [current_buf]作爲條件變量NSConditionLock。如果緩衝區未被標記爲新的,那麼該線程將被鎖定,等待前一個線程寫入新數據。這部分似乎工作正常。

主要問題是我需要同步這兩個方向。如果由於某種原因讀取線程花費時間過長,並且處理線程已經完成處理所有緩衝區,則處理線程需要等待,反之亦然。

我不確定NSConditionLock是做到這一點的適當方法。

+1

是的。線程很難。 – bbum

回答

2

我會打開它的頭。正如你所說,線程很難,線程的多路同步更困難。基於隊列的併發性通常更加自然。

定義三個隊列;讀隊列,寫隊列和處理隊列。然後使用一條規則,規定沒有緩衝區應該在時間在多於一個隊列中入隊。

也就是說,一個緩衝區可以被排隊到讀隊列上,一旦讀完,排隊到處理隊列中,並且一旦完成處理,排隊到寫隊列中。

你可以使用緩衝區的堆棧,如果你想要,但通常情況下,相對於加工的成本分攤的成本相當便宜,因此,排隊換讀也可以做分配,同時離隊,once-書面可以做免費的。

這對於使用GCD進行編碼非常簡單。請注意,如果您確實需要並行性,那麼您的各種隊列實際上只會被限制,使用信號量(可能是共享的)將隊列排入全局併發隊列。

還要注意,這個設計比你當前使用的有一個明顯的優勢,它不使用鎖。作爲隊列管理的一部分,唯一的鎖隱藏在GCD API的下方,但是這對您的代碼是有效的。

+1

我想保持代碼儘可能便攜,因此使用NSLocks/pthreads。我最終做的是使用NSConditionLock和NSCondition的組合。經過很多測試,似乎工作正常。使用直線C移植到Linux可能會有點棘手,但至少我知道這是可能的,因爲Cocoa的NSLocks在內部使用pthread。 – Synthetix

1

你見過那麼Apple Concurrency Programming Guide ?

它建議移動從線程和鎖併發模型走幾個最好的方法。例如,使用「操作隊列」不僅可以減少和簡化代碼,加快開發速度並提高性能。

有時你需要使用線程,並且你已經有了正確的想法。您將需要不斷添加鎖,並且每個鎖都會呈指數級增長,直到您無法理解您自己的代碼。然後你可以開始在隨機的地方添加鎖。然後你被搞砸了。

閱讀併發指南,然後遵循bbum的建議。

+1

* ...你無法理解你自己的代碼。然後你可以開始在隨機的地方添加鎖。那你就搞砸了。*智慧的話,那。 – bbum