【发布时间】:2018-02-20 21:28:10
【问题描述】:
我正在尝试编写一个多线程遍历树结构的 C# 系统。另一种看待这一点的方式是 BlockingCollection 的消费者也是生产者。
我遇到的问题是告诉一切何时完成。 我真正需要的测试是查看是否所有线程都在 TryTake 上。 如果它们是,那么一切都已经完成,但我找不到一种方法来测试它或用任何有助于实现这一点的东西来包装它。
据我所知,下面的代码是这个代码的一个非常简单的例子,但是有一个条件,这个代码可能会失败。如果第一个线程刚刚通过 test.TryTake(out v,-1) 并且还没有执行 s.Release();它只是从集合中拉出最后一项,而第二个线程刚刚执行了 if(s.CurrentCount == 0 && test.Count ==0) 这可能返回 true,并错误地开始完成。
但随后第一个线程将继续并尝试向集合中添加更多内容。
如果我能画出线条:
if (!test.TryTake(out v, -1))
break;
s.Release();
atomic 那么我相信这段代码会起作用。 (这显然是不可能的。)
但我不知道如何修复这个缺陷。
class Program
{
private static BlockingCollection<int> test;
static void Main(string[] args)
{
test = new BlockingCollection<int>();
WorkClass.s = new SemaphoreSlim(2);
WorkClass w0 = new WorkClass("A");
WorkClass w1 = new WorkClass("B");
Thread t0 = new Thread(w0.WorkFunction);
Thread t1 = new Thread(w1.WorkFunction);
test.Add(10);
t0.Start();
t1.Start();
t0.Join();
t1.Join();
Console.WriteLine("Done");
Console.ReadLine();
}
class WorkClass
{
public static SemaphoreSlim s;
private readonly string _name;
public WorkClass(string name)
{
_name = name;
}
public void WorkFunction(object t)
{
while (true)
{
int v;
s.Wait();
if (s.CurrentCount == 0 && test.Count == 0)
test.CompleteAdding();
if (!test.TryTake(out v, -1))
break;
s.Release();
Console.WriteLine(_name + " = " + v);
Thread.Sleep(5);
for (int i = 0; i < v; i++)
test.Add(i);
}
Console.WriteLine("Done " + _name);
}
}
}
【问题讨论】:
-
Another way to look at this is where the consumer of the BlockingCollection is also the producer.这实际上是 ConcurrentBag 可能更高效的非常非常罕见的情况之一 -
所以.. 你需要知道的是,当最后一个线程刚刚完成处理树的最后一个节点时,是吗?
标签: c# multithreading locking