use*_*631 2 .net c# producer-consumer c#-4.0
我正在使用BlockingCollection生产者消费者模式,我有一个例外,我想写一个专利 - 只有谷歌的两个结果!预期是"CompleteAdding可能不会与添加到集合中同时使用",并且当我TryAdd在BlockingCollection上时会发生以下情况:
public void EnqueueTask(T item)
{
if (!_cancellationTokenSource.IsCancellationRequested)
{
_workerQueue.Add(item);
}
}
Run Code Online (Sandbox Code Playgroud)
在CompleteAdding处理Consumer-Producer包装类时调用它:
public void Dispose()
{
if (!_IsActive)
return;
_IsActive = false;
_cancellationTokenSource.Cancel();
_workerQueue.CompleteAdding();
// Wait for the consumer's thread to finish.
for (int i = 0; i < _workers.Length; ++i)
{
Task t1 = Task.Factory.StartNew(() =>
{
try
{
if (!_workers[i].Join(4000))
LogWriter.Trace("Failed to join thread", "ThreadFailureOnDispose");
}
catch (Exception ex)
{
OnLogged(ex.Message + ex.StackTrace);
}
});
}
// Release any OS resources.
}
Run Code Online (Sandbox Code Playgroud)
微软的任何人都有想法?我应该在取消之后和调用CompleteAdding之前睡觉吗?
看看这段代码:
for (int i = 0; i < _workers.Length; ++i)
{
Task t1 = Task.Factory.StartNew(() =>
{
try
{
if (!_workers[i].Join(4000)) << == Here
LogWriter.Trace("Failed to join thread", "ThreadFailureOnDispose");
}
Run Code Online (Sandbox Code Playgroud)
在_workers[i].Join(4000),价值i不是你想象的那样.再试一次:
for (int i = 0; i < _workers.Length; ++i)
{
int j = i; // copy
Task t1 = Task.Factory.StartNew(() =>
{
try
{
if (!_workers[j].Join(4000)) // j
LogWriter.Trace("Failed to join thread", "ThreadFailureOnDispose");
}
Run Code Online (Sandbox Code Playgroud)
在您的版本中,捕获变量"i"并且所有任务使用相同的var.除了前几个之外的所有部分都会看到i == _workers.Length因为它们在for循环完成后执行.
这是一个经典的lambda +捕获var问题.