简体   繁体   English

Interlocked.Exchange的安全性如何?

[英]How safe are Interlocked.Exchange?

Beeing a threading noob, I'm trying to find a way w/o locking objects that allows me to enqueue a threadpool task, in such way that it has a max degree of parallelism = 1. Beeing一个线程菜鸟,我正试图找到一种不用锁定对象的方法,允许我将线程池任务排入队列,使其具有最大并行度= 1。

Will this code do what I think it does? 这段代码会做我认为的吗?

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);
    }
}

That is, in a threadsafe way enqueue the Run method if the status is Idle . 也就是说,如果状态为Idle ,则以线程安全的方式将Run方法排入队列。 It seems to work fine in my tests, but since this is not my area, I'm not sure. 它似乎在我的测试中工作正常,但由于这不是我的领域,我不确定。

Yes, this will do what you want. 是的,这将做你想要的。 It will never allow you to get a return value of Idle when in fact status is Busy, and it will set status to Busy in the same operation, with no chance of a conflict. 当实际状态为Busy时,它永远不会允许您获得Idle的返回值,并且它将在同一操作中将状态设置为Busy,不会发生冲突。 So far so good. 到现在为止还挺好。

However, if you're using a ConcurrentQueue<T> later on, why do you even do this? 但是,如果您稍后使用ConcurrentQueue<T> ,为什么还要这样做呢? Why do you use a ThreadPool to enqueue Run over and over again, instead of just having a single thread continually take data from the concurrent queue using TryDequeue? 为什么使用ThreadPool一次又一次地运行Run,而不是让一个线程使用TryDequeue连续从并发队列中获取数据?

In fact, there is a producer-consumer collection that is specifically designed for this, the BlockingCollection<T> . 事实上,有一个专门为此设计的生产者 - 消费者集合, BlockingCollection<T> Your consumer thread would just call Take (with a cancellation token if necessary - probably a good idea) and that either returns a value as in ConcurrentQueue<T>; 您的消费者线程只会调用Take (如果需要,可以使用取消令牌 - 可能是个好主意),并且返回ConcurrentQueue<T>; or if no value is available, blocks the thread until there is something to take. 或者如果没有可用的值,则阻塞线程直到有可能采取的措施。 When some other thread adds an item to the collection, it will notify as many consumers as it has data for (in your case, no need for anything complex, since you only have one consumer). 当一些其他线程将一个项目添加到集合时,它将通知尽可能多的消费者,因为它有数据(在您的情况下,不需要任何复杂的,因为您只有一个消费者)。

That means you only have to handle starting and stopping a single thread, which will run an "infinite" cycle, which will call col.Take , while the producers call col.Add . 这意味着您只需要处理启动和停止单个线程,该线程将运行“无限”循环,这将调用col.Take ,而生产者调用col.Add

Of course, this assumes you have .NET 4.0+ available, but then again, you probably do, since you're using ConcurrentQueue<T> . 当然,这假设你有.NET 4.0+可用,但是你可能会这样做,因为你正在使用ConcurrentQueue<T>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM