Interlocked.Exchange的安全性如何?

时间:2014-01-08 11:50:00

标签: c# multithreading interlocked

Beeing一个线程菜鸟,我正试图找到一种不用锁定对象的方法,允许我将线程池任务排入队列,使其具有最大并行度= 1。

这段代码会做我认为的吗?

private int status;
private const int Idle = 0;
private const int Busy = 1;

private void Schedule()
{
    // only schedule if we idle
    // we become busy and get the old value to compare with
    // in an atomic way (?)
    if (Interlocked.Exchange(ref status, Busy) == Idle)
    {
        ThreadPool.QueueUserWorkItem(Run);
    }
}

也就是说,如果状态为Run,则以线程安全的方式将Idle方法排入队列。 它似乎在我的测试中运行良好,但由于这不是我的区域,我不确定。

1 个答案:

答案 0 :(得分:1)

是的,这会做你想要的。当实际状态为Busy时,它永远不会允许您获得Idle的返回值,并且它将在同一操作中将状态设置为Busy,不会发生冲突。到目前为止一切都很好。

但是,如果您稍后使用ConcurrentQueue<T>,为什么还要这样做呢?为什么使用ThreadPool一次又一次地运行Run,而不是让一个线程使用TryDequeue连续从并发队列中获取数据?

事实上,有一个专门为此设计的生产者 - 消费者集合,BlockingCollection<T>。您的消费者线程只会调用Take(如果需要,可以使用取消令牌 - 可能是个好主意)并且如果没有值可用则返回ConcurrentQueue<T>; 中的值,阻止线程,直到有东西要采取。当一些其他线程将一个项目添加到集合时,它将通知尽可能多的消费者,因为它有数据(在您的情况下,不需要任何复杂的,因为您只有一个消费者)。

这意味着您只需处理启动和停止单个线程的操作,该线程将运行“无限”循环,调用col.Take,而生产者调用col.Add

当然,这假设你有.NET 4.0+可用,但是你可能会这样做,因为你正在使用ConcurrentQueue<T>