【问题标题】:Does Task Parallel Library (TPL) handle race condition任务并行库 (TPL) 是否处理竞争条件
【发布时间】:2015-08-20 18:20:12
【问题描述】:

我试图了解 Task Parallel 库相对于使用传统多线程的好处,当我想到以下情况时,我一直在想它是处理竞争条件还是我们需要在代码中处理它?

这是我的代码:

 int depdt = 0;    
 Parallel.For(1, 10, mem =>
        {

            for (int dep = 1; dep <= 10; dep++)
            {
                depdt = dep;
                Console.WriteLine("MEMBER: " + mem + " " + "Dependent: " + dep);
            }

            Console.WriteLine("Dep Value: " + depdt + " " + "mem: " + mem);
        });
        Console.ReadKey();

我运行了几次,没有看到任何线程干扰/覆盖“depdt”变量。但我需要确认这一点。 (或)为了使其线程安全,我应该手动创建一个类的实例并像下面的代码那样实现它以避免竞争条件

 int depdt = 0;
        Parallel.For(1, 10, mem =>
        {
              Worker worker = new Worker();
              worker.DoWork(mem);

        });
        Console.ReadKey();

  public class Worker
{
    public void DoWork(int mem)
    {

        int depdt = 0;
        for (int dep = 1; dep <= 10; dep++)
        {
            depdt = dep;
            Console.WriteLine("MEMBER: " + mem + " " + "Dependent: " + dep);
        }

        Console.WriteLine("Dep Value: " + depdt  +" "+ "mem: "+ mem);
    }
}

回复@yms: 我的意思是当使用普通线程时,变量 depdt 变得不可靠。这是我的代码:

for (int mem = 1; mem <= 10; mem++)
        {
            var t= new Thread(state =>
            {
                for (int dep = 1; dep <= 10; dep++)
                {
                    depdt = dep;
                    Console.WriteLine("MEMBER: " + mem + " " + "Dependent: " + dep);
                }

                Console.WriteLine("Dep Value: " + depdt + " " + "mem: " + mem);
            });

            t.Start(string.Format("Thread{0}", mem));
        }
        Console.ReadKey();

这是我的输出屏幕:事实上 mem 和 dep 变量都变得不可靠了

【问题讨论】:

  • 注意 4 字节 int are usually atomics 的变量赋值。此外,我认为不需要引入新类,您可以在 lambda 表达式中使用局部变量
  • @yms 我的意思是通过使用普通线程,您通常会进入“depdt”变量变得不可靠的状态。请参阅下面的代码及其使用 Threads 的结果
  • @yms 我在回答您的评论的问题中添加了更多信息。谢谢

标签: c# .net multithreading task-parallel-library race-condition


【解决方案1】:

如果您希望您的程序始终写入Dep Value: 10,那么是的,您的程序会受到可能导致打印其他值的竞争条件的影响。为了演示这个问题,只需在内部循环中引入一个延迟:

int depdt = 0;
Parallel.For(1, 10, mem =>
{
    for (int dep = 1; dep <= 10; dep++)
    {
        depdt = dep;
        Console.WriteLine("MEMBER: " + mem + " " + "Dependent: " + dep);
        Thread.Sleep(mem * 100);   // delay introduced here
    }
    Console.WriteLine("Dep Value: " + depdt + " " + "mem: " + mem);
});
Console.ReadKey();

您的程序看起来表现正确的原因是内部循环执行时间非常短,可能在分配给线程的单个时间段内完成。

为避免竞争条件,您只需将depdt 声明移动到内部 传递给Parallel.For 的匿名函数中。这将导致每个线程都有自己的变量,从而避免冲突。

Parallel.For(1, 10, mem =>
{
    int depdt = 0;
    for (int dep = 1; dep <= 10; dep++)
    {
        depdt = dep;
        Console.WriteLine("MEMBER: " + mem + " " + "Dependent: " + dep);
    }
    Console.WriteLine("Dep Value: " + depdt + " " + "mem: " + mem);
});

【讨论】:

  • 谢谢道格拉斯。所以,要点是 TPL 没有任何内置机制来处理竞争条件,它应该在我们的代码中处理。
  • @marak: Shared memory parallelism 天生就容易受到竞争条件的影响。由于您将变量声明为在所有线程之间共享,因此预计多个线程能够同时访问它。这实际上是有时需要的行为,例如用于终止后台操作的哨兵标志。
【解决方案2】:

没有。任务并行库默认不处理竞争条件。您需要注意同步对共享资源的访问。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-07
    • 2011-09-22
    • 1970-01-01
    • 2019-04-10
    • 2020-07-12
    • 2011-04-01
    相关资源
    最近更新 更多