[英]Thread-safe C++ stack
我是C ++的新手,正在編寫一個多線程的應用程序,不同的編寫器將把對象推到堆棧上,讀者將它們從堆棧中拉出來(或者至少將指針推到一個對象上)。
是否有內置於C ++中的結構可以在不添加鎖定代碼等的情況下處理此問題? 如果沒有,Boost庫怎么樣?
編輯:
你好。 感謝最初的好答案。 我想我認為這可能是內置的一個原因是我純粹在x86空間思考並且認為指針的PUSH / POP應該是指令級別的原子動作。
我不確定我最初的預感是否正確,但我想在所有平台上都不一定如此。 雖然如果在x86上運行,你是否會將原子PUSH和POP發送到堆棧中,如果是這樣,這實際上是否使它無鎖?
是的: Boost.Thread很棒,應該很好地滿足你的需求。 (現在,很多人都說你幾乎可以將Boost視為內置功能。)
仍然沒有可以使用開箱即用的類,但是一旦掌握了同步原語,實現自己的線程安全包裝器(例如std::stack
就非常簡單了。 它可能看起來像這樣(沒有實現每個方法......):
template <typename T> class MyThreadSafeStack {
public:
void push(const T& item) {
boost::mutex::scoped_lock lock(m_mutex);
m_stack.push(item);
}
void pop() {
boost::mutex::scoped_lock lock(m_mutex);
m_stack.pop();
}
T top() const { // note that we shouldn't return a reference,
// because another thread might pop() this
// object in the meanwhile
boost::mutex::scoped_lock lock(m_mutex);
return m_stack.top();
}
private:
mutable boost::mutex m_mutex;
std::stack<T> m_stack;
}
如果您不熟悉 C ++,請了解RAII 。 與此案相關,Boost.Thread有“范圍鎖定”類,因為忘記釋放鎖定很難讓自己在腿上射擊。
如果您發現自己編寫的代碼如下:
void doStuff() {
myLock.lock();
if (!condition) {
reportError();
myLock.unlock();
return;
}
try {
doStuffThatMayThrow();
}
catch (std::exception& e) {
myLock.unlock();
throw e;
}
doMoreStuff();
myLock.unlock();
}
,那么你應該說不,然后去RAII(語法不直接來自Boost):
void doStuff() {
scoped_lock lock;
if (!condition) {
reportError();
return;
}
doStuffThatMayThrow();
doMoreStuff();
}
關鍵是當scoped_lock
對象超出范圍時,它的析構函數會釋放資源 - 在本例中是鎖定。 無論您是通過拋出異常退出作用域,還是執行您的同事在函數中間偷偷添加的奇數return
語句,或者只是到達函數末尾,這都會發生。
目前的C ++標准根本不涉及線程,所以第一個問題的答案是否定的。 一般而言,將鎖定構建到基本數據結構中是一個壞主意,因為它們沒有足夠的信息來正確和/或有效地執行它。 相反,鎖定應該在使用數據結構的類中執行 - 換句話說,在您自己的應用程序類中。
AFAIK,沒有內置的C ++支持。 您必須使用簡單的同步工具同步堆棧操作。 如果線程屬於同一個進程,則CriticalSection會執行,否則為Mutex。
如果您不想使用鎖定,則需要使用無鎖堆棧。 這實際上並不那么難(無鎖隊列更難)。 您確實需要特定於平台的比較交換原語,例如Windows上的InterlockedCompareExchange,但這並不難以抽象。
請參閱此處以獲取C#中的示例:
如果您在Windows上運行,SLIST將實現無鎖堆棧(具有SLIST_HEADER & SLIST_ENTRY
結構)。
該算法使用互鎖函數使用相當簡單的推/彈單鏈接列表堆棧來實現。 唯一不明顯的項目是計數器增量以避免ABA問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.