我正在编写一个多线程应用程序,我担心2个线程访问队列
线程1将项目放入队列进行处理 线程2从队列中删除要处理的项目
线程1每分钟运行一次,因为它正在拉动数据的性质。 线程2始终在运行,它从队列中删除一个项目并休眠100毫秒。我必须这样做,以确保我不会淹没它在项目出列时所调用的服务。
我假设在添加或删除项目时,两个线程都应该锁定队列。有进一步的考虑吗?例如,假设线程1有一个锁,而线程2试图访问它。线程2是否只知道在锁定被移除后等待并恢复?
使用ConcurrentQueue和TryDequeue会更好吗?如果它失败了,那么只需要100毫秒的睡眠时间吗?
提前致谢
答案 0 :(得分:8)
如果你像我在NuGet的VS控制台调度程序中那样使用BlockingCollection<T>
来实现我的PostKey / WaitKey,那就更容易了。消费线程调用Take(...)
,它将阻塞,直到另一个线程调用Add(...)
。没有必要进行民意调查。此外,您可能希望将取消令牌传递给Take
方法,以便另一个线程可以停止使用者线程,如果它当前正在等待永远不会来的Add
。以下是相关方法:
private readonly BlockingCollection<VsKeyInfo> _keyBuffer =
new BlockingCollection<VsKeyInfo>();
private CancellationTokenSource _cancelWaitKeySource;
// place a key into buffer
public void PostKey(VsKeyInfo key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
_keyBuffer.Add(key);
}
// signal thread waiting on a key to exit Take
public void CancelWaitKey()
{
if (_isExecutingReadKey && !_cancelWaitKeySource.IsCancellationRequested)
{
_cancelWaitKeySource.Cancel();
}
}
// wait for a key to be placed on buffer
public VsKeyInfo WaitKey()
{
try
{
// raise the StartWaitingKey event on main thread
RaiseEventSafe(StartWaitingKey);
// set/reset the cancellation token
_cancelWaitKeySource = new CancellationTokenSource();
_isExecutingReadKey = true;
// blocking call
VsKeyInfo key = _keyBuffer.Take(_cancelWaitKeySource.Token);
return key;
}
catch (OperationCanceledException)
{
return null;
}
finally
{
_isExecutingReadKey = false;
}
}
答案 1 :(得分:2)
只要您锁定相同的“sync”对象,线程2将等待线程1,反之亦然。我认为ConcurrentQueue是一个好主意,因为它已被指定为线程安全。
答案 2 :(得分:1)
ConcurrentQueue
是线程安全的,因此您不需要锁定,只需调用TryDequeue
即可,没有其他特殊编码就可以了。不要迭代它,根据文档,它会在迭代时快照(除非那是你想要的):http://msdn.microsoft.com/en-us/library/dd287144.aspx
枚举表示队列内容的即时快照。在调用 GetEnumerator 后,它不会反映对集合的任何更新。枚举器可以安全地与队列的读取和写入同时使用。
老实说,我认为只要让线程1在需要完成任务并使用某种限制同步(如AutoResetEvent
)
答案 3 :(得分:1)
如果你要睡100码,你可以任意方式实现队列,只要它是线程安全的。一个带锁/互斥锁的简单队列,一个ConcurrentQueue,它们都很好。
'例如,说线程1有一个锁,而线程2试图访问它。线程2只是知道等待并在锁定被移除后恢复“ - 线程2等待锁定被释放,是的。