對於傳統的單塊循環緩衝區我覺得這根本無法與原子操作安全進行。你需要在一次閱讀中這麼做。假設你有一個具有這樣的結構:
uint8_t* buf;
unsigned int size; // Actual max. buffer size
unsigned int length; // Actual stored data length (suppose in write prohibited from being > size)
unsigned int offset; // Start of current stored data
在你需要做以下的讀取(這是我如何實現它無論如何,你可以交換一些步驟就像我以後會討論):
- 檢查讀取長度不超過存儲長度
- 檢查偏移+閱讀長度不超過緩衝區邊界
- 讀取數據輸出
- 增加所抵消,減少長
你應該怎麼做同步(如此原子)才能使這項工作?事實上,合併步驟1和4在一個原子一步,或澄清:這樣做同步:
- 檢查read_length,這可能是某事像
read_length=min(read_length,length);
- 與read_length下降長度:
length-=read_length
- 得到一個本地副本從偏移
unsigned int local_offset = offset
- 增加與read_length偏移:
offset+=read_length
之後你可以做一個的memcpy(或W從你的local_offset開始,檢查你的讀是否超過循環緩衝區大小(分爲2個memcpy's),...。這是'相當'的線程安全,您的寫入方法仍然可以覆蓋您正在閱讀的內存,所以請確保您的緩衝區足夠大,以最大限度地減少這種可能性。儘管我可以想象你可以在原子操作中組合3和4(我猜這就是他們在鏈表列表中所做的事情),甚至1和2,但是我看不到你在一個原子操作:)。
然而,如果您的消費者非常聰明,並且總是知道要閱讀什麼,那麼您可以嘗試刪除「長度」。您還需要一個新的woffset變量,因爲用於確定寫入偏移量的(offset + length)%大小的舊方法不再適用。請注意,這與鏈接列表的情況很接近,實際上您總是從列表中讀取一個元素(=固定的,已知大小)。同樣在這裏,如果你把它作爲一個循環鏈表,你可以閱讀到很多,或者寫下你當時正在閱讀的位置!
最後:我的建議,只是去鎖,我使用CircularBuffer類,完全安全的閱讀&寫)實時720p60視頻流媒體,我沒有速度問題的鎖定。
有限公司大小的緩衝區意味着,如果有一個在它沒有空的空間製片人可能會失敗。你能接受嗎? – doublep 2010-04-23 22:38:09
另請注意,在C++中,您可以將自己的分配器提供給'std :: list'。由於你只有一個生產者,所以這個分配器不需要同步。例如,它可以從預先分配的緩衝區中「分配」列表節點,並且當空間用完時,使用全局同步的'malloc()'''''''''''''''''''''''''''''''''''這意味着它只會在1%的通話中使用同步。 – doublep 2010-04-23 22:41:52
如果你想優化線程的內存使用率,tcmalloc是一個很好的庫。由於它爲每個線程維護內存池,因此可能避免內存例程序列化問題。 – 2010-04-23 22:49:58