如何使 Stack.Pop 线程安全

Posted

技术标签:

【中文标题】如何使 Stack.Pop 线程安全【英文标题】:How to make Stack.Pop threadsafe 【发布时间】:2011-01-27 18:45:41 【问题描述】:

我正在使用 in this question 发布的 BlockingQueue 代码,但我意识到鉴于我的程序运行方式,我需要使用堆栈而不是队列。我将其转换为使用 Stack 并根据需要重命名该类。为了提高性能,我删除了 Push 中的锁定,因为我的生产者代码是单线程的。

我的问题是(现在)线程安全堆栈上的线程如何知道它何时为空。即使我在 Count 周围添加另一个线程安全包装器,像 Push 和 Pop 那样锁定底层集合,我仍然会遇到访问 Count 然后 Pop 不是原子的竞争条件。

我看到的可能的解决方案(这是首选,我错过了任何更好的解决方案吗?):

    消费线程捕获由 Pop() 抛出的 InvalidOperationException。 当 _stack->Count == 0 时,Pop() 返回一个 nullptr,但是 C++-CLI 没有 default() 运算符 ala C#。 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;
;

【问题讨论】:

"为了提高性能,我删除了 Push 中的锁定,因为我的生产者代码是单线程的。"你这是什么意思?你只有一个制作人?您的生产者代码是否与消费者同时运行? 是的,我只有一个生产者,而且我的生产者代码不会与消费者同时运行。它先运行,然后使用生产者生成的 ThreadSafeStack 运行多个消费者。 【参考方案1】:

就个人而言,我会使用您的选项 3.,但重命名此 TryPop()。

这将使它的行为更像框架的 ConcurrentQueue&lt;T&gt;.TryDequeue(在 .NET 4 中)。


编辑:

我会这样声明:

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

在您的实现中,您只需在方法体中设置 T 值...

【讨论】:

完全不熟悉c++-cli中如何使用out参数,有链接或示例代码吗? 鉴于如果堆栈为空,TryPop 应该返回一个 nullptr,您是否建议在我调用 TryPop 的地方传入一个 nullptr 或确保我将 out 参数设置为一个 nullptr?同样,我不确定如何执行与 default(T) 等效的 c#。我发现了这个:***.com/questions/1962600/… @user260197:我的 C++/CLI 有点生疏,但我认为你只需这样做:result = T();【参考方案2】:

选项 #3 是可行的方法,Marc Gravell 发布了一个出色的 BufferedQueue/BlockingQueue 实现,他称之为SizeQueue

Creating a blocking Queue<T> in .NET?

鉴于 Marc 的队列示例,在堆栈中交换应该很容易,并且可以以类似的方式工作。

【讨论】:

以上是关于如何使 Stack.Pop 线程安全的主要内容,如果未能解决你的问题,请参考以下文章

如何使 ObservableCollection 线程安全?

如何轻松使 std::cout 线程安全?

如何使这个线程安全

如何使 Swift 类单例实例线程安全?

如何使用 Platform.runLater 使 JavaFX 线程安全

如何使CircularFifoQueue线程安全?