2012-01-22 97 views
1

我爲SFML寫了一個線程渲染器,它將指針指向可繪製對象並將它們存儲在向量中以繪製每一幀。開始向矢量添加對象並將對象移除到矢量將經常導致分段錯誤(SIGSEGV)。爲了試圖解決這個問題,我會添加需要刪除/添加到隊列中的對象,以便稍後移除(繪製框架之前)。這似乎解決了它,但最近我已經注意到,如果我一次添加多個對象(或者添加/刪除它們足夠快),我會得到相同的SIGSEGV。C++線程安全vector.erase

我應該在向量中添加/刪除時使用鎖嗎?

+0

我認爲一個靜態鎖就足夠了。 –

回答

1

我應該在向量中添加/刪除時使用鎖嗎?

是的。如果您同時使用來自兩個線程的向量並重新分配,則後備分配可能會換出並釋放到其他線程的後面。另一個線程將讀取/寫入釋放的內存,或用於另一個無關分配的內存。

2

您需要了解線程安全性,以保證C++標準(以及可能的併發系統的C++ 2003的實現)給出。標準容器在以下意義上是線程安全的:

  1. 可以有多個併發線程讀取同一個容器。
  2. 如果有一個線程修改一個容器,那麼不應該有併發線程讀取或寫入同一個容器。
  3. 不同的容器是相互獨立的。

很多人誤解容器的線程安全的意思,這些規則是由容器實現地稅:他們都沒有!遵守這些規則是你的責任。

這些不是,實際上不能由容器強加的原因是它們沒有適合這個的接口。例如,考慮下面的瑣碎一段代碼:

if (!c.empty() { 
    auto value = c.back(); 
    // do something with the read value 
} 

容器可以控制到empty()back()接入到呼叫。然而,在這些調用之間,它必然需要釋放任何類型的同步設施,即在線程嘗試讀取c.back()時容器可能再次變空!基本上有兩種方法來解決這個問題:

  1. 您需要使用外部鎖定,如果有可能的是併發線程可改變容器跨越這是某種形式的相互依存訪問的整個範圍。
  2. 您將容器的接口更改爲monitors。但是,容器接口並不適合在這個方向上進行改變,因爲監視器基本上只支持「火和忘」式的接口。

這兩種策略都有它們的優點,標準庫容器明顯支持第一種樣式,即當與至少一個修改容器的線程同時使用時,它們需要外部鎖定。如果首先只有一個線程使用它們,它們不需要任何類型的鎖定(無論是內部還是外部)。這實際上是他們設計的場景。爲它們提供的線程安全保證已經到位,以確保沒有內部工具不是線程安全的,比如每個對象迭代器對象或多線程共享的內存分配工具,而不是線程安全的,等等

要回答原始問題:是的,您需要使用外部同步,例如以互斥鎖的形式,如果您在一個線程中修改容器並在另一個線程中讀取它。