2010-03-15 68 views
1

我使用的BlockingQueue代碼張貼in this question,但我意識到我需要使用堆棧而不是給定我的程序如何運行的隊列。我將它轉換爲使用堆棧並根據需要重命名類。爲了提高性能,我刪除了Push中的鎖定,因爲我的生產者代碼是單線程的。如何使Stack.Pop線程安全

我的問題是如何可以線程安全棧上的線程工作知道什麼時候它是空的。即使我添加了另一個線程安全包裝器,這個包圍着像Push和Pop這樣的底層集合的Count,我仍然遇到訪問Count和Pop的競爭條件不是原子的。

可能的解決方案,因爲我看到他們(這是首選和我失去了任何會更好地工作?):

  1. 消費者線程追趕()波普拋出InvalidOperationException異常。
  2. Pop()在_stack-> Count == 0時返回nullptr,但是C++ - CLI沒有默認的()運算符ala C#。
  3. Pop()返回一個布爾值並使用輸出參數返回彈出的元素。

這裏是我使用的是現在的代碼:

generic <typename T> 
public ref class ThreadSafeStack 
{ 
public: 
    ThreadSafeStack() 
    { 
    _stack = gcnew Collections::Generic::Stack<T>(); 
    } 

public: 
    void Push(T element) 
    { 
    _stack->Push(element); 
    } 

    T Pop(void) 
    { 
    System::Threading::Monitor::Enter(_stack); 
    try { 
     return _stack->Pop(); 
    } 
    finally { 
     System::Threading::Monitor::Exit(_stack); 
    } 
    } 

public: 
    property int Count { 
    int get(void) 
    { 
     System::Threading::Monitor::Enter(_stack); 
     try { 
     return _stack->Count; 
     } 
     finally { 
     System::Threading::Monitor::Exit(_stack); 
     } 
    } 
    } 

private: 
    Collections::Generic::Stack<T> ^_stack; 
}; 
+0

「爲了提高性能,我刪除了Push中的鎖定,因爲我的生產者代碼是單線程的。」 這是什麼意思?你只有一個製片人?您的生產者代碼是否與消費者同時運行? – tony 2010-03-15 21:04:39

+0

是的,我只有一個生產者,並且我的生產者代碼不會與消費者同時運行。它首先運行,然後使用生產者生成的ThreadSafeStack運行多個消費者。 – 2010-03-15 21:38:52

回答

4

就個人而言,我會用你的選項3,但重命名此TryPop()。

這會使其表現更像框架的ConcurrentQueue<T>.TryDequeue(在.NET 4中)。


編輯:

我這樣聲明:

public: 
bool TryPop([Out] T% result); 

在您的實現,您只需設置T值在方法的身體......

+0

不熟悉如何在C++中使用參數 - cli,任何鏈接或示例代碼? – 2010-03-15 17:11:51

+0

@ user260197:我只是爲你添加聲明... – 2010-03-15 17:18:32

+0

鑑於如果堆棧爲空,TryPop應該返回nullptr,你是否建議傳入一個nullptr,我將其稱爲TryPop或確保將out參數設置爲nullptr?再次,我不知道如何做的默認(T)的C#等效。我發現這個:http:// stackoverflow。com/questions/1962600/what-is-the-c-cli-equivalent-to-cs-defaultt – 2010-03-15 17:30:39

2

選項#3是要走的路,Marc Gravell發佈了BufferedQueue/BlockingQueue的優秀實施方案,他稱之爲SizeQueue

Creating a blocking Queue<T> in .NET?

鑑於Marc的隊列示例,它應該很容易交換堆棧,並且它可以以類似的方式工作。

+0

謝謝,這是一個很好的鏈接。 – 2010-03-15 20:31:54