我有三个任务,一个是制作人,然后是消费者,最后一个是在完成前两个任务后打印一些东西。但是代码没有到达最后一个任务,这意味着没有打印。
while (true)
{
ThreadEvent.WaitOne(waitingTime, false);
lock (SyncVar)
{
collection = new BlockingCollection<string>(4);
Task producer = Task.Run(() =>
{
if (list.Count > 0)
Console.WriteLine("Block begin");
while (!collection.IsAddingCompleted)
{
var firstItem = list.FirstOrDefault();
collection.TryAdd(firstItem);
list.Remove(firstItem);
}
collection.CompleteAdding();
});
Task consumer = Task.Run(() => DoConsume());
Task endTask = consumer.ContinueWith(i => Console.WriteLine("Block end"));// not print this line, why?
Task.WaitAll(producer, consumer, endTask);
if (ThreadState != State.Running) break;
}
}
请查看我的代码逻辑。
修改
对于“DoConsume”,它很复杂。
public void DoConsume()
{
if (collection.Count > 0)
Console.WriteLine("There are {0} channels to be processed.", collection.Count);
var workItemBlock = new ActionBlock<string>(
workItem =>
{
bool result =ProcessEachChannel(workItem);
});
foreach (var workItem in collection.GetConsumingEnumerable())
{
workItemBlock.Post(workItem);
}
workItemBlock.Complete();
}
答案 0 :(得分:0)
问题是你的制作人永远不会完成:
// This will run until after CompleteAdding is called
while (!collection.IsAddingCompleted)
{
var firstItem = list.FirstOrDefault();
collection.TryAdd(firstItem);
list.Remove(firstItem);
}
//... which doesn't happen until after the loop
collection.CompleteAdding();
您似乎只是想添加列表中的所有项目,这应该很简单:
Task producer = Task.Run(() =>
{
if (list.Count > 0)
Console.WriteLine("Block begin");
while(list.Any())
{
var firstItem = list.First();
collection.TryAdd(firstItem);
list.Remove(firstItem);
}
collection.CompleteAdding();
});
或者,更简单的方法:
Task producer = Task.Run(() =>
{
if (list.Count > 0)
Console.WriteLine("Block begin");
foreach(var item in list)
{
collection.TryAdd(item);
}
list.Clear();
collection.CompleteAdding();
});
答案 1 :(得分:0)
我使用了Reed Copsey的代码,但错误仍然存在。只是无法弄清楚原因。
我认为我的代码存在while (!collection.IsAddingCompleted)
的缺陷。
因为集合的边界为4,所以假设集合中还有两个项目。条件collection.IsAddingCompleted
永远不会被满足,因此代码无法跳出while循环。
我重写了代码,看起来很好。代码类似MSDN.我使用Take
来检索集合中的元素。
while (true)
{
ThreadEvent.WaitOne(waitingTime, false);
lock (SyncVar)
{
collection = new BlockingCollection<string>(4);
DoWork dc = new DoWork();
Task consumer = Task.Run(() =>
{
while (!collection.IsCompleted)
{
string data = "";
try
{
if (collection.Count > 0)
data = collection.Take();
}
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
}
if (data != "")
{
bool result = dc.DoConsume(data);
}
}
});
Task producer = Task.Run(() =>
{
if (list.Count > 0)
Console.WriteLine("Block begin");
foreach (var item in list)
{
collection.Add(item);
}
list.Clear();
collection.CompleteAdding();
});
Task endTask = consumer.ContinueWith(i => Console.WriteLine("Block end"));
Task.WaitAll(producer, consumer, endTask);
if (ThreadState != State.Running) break;
}