理解线程为什么计数不增加

时间:2016-11-10 18:27:05

标签: c# multithreading console thread-safety

我不会解释为什么使用此代码

static void Main(string[] args)
    {
        Console.WriteLine("START PROGRAMN-----------------------------------");
        test();
        Console.WriteLine("END PROGRAMN-----------------------------------");
        Console.Read();
    }
    [ThreadStatic]
    private static int i;
    private static void test()
    {
        for (i = 0; i < 2; i++)
        {
            var bw = new BackgroundWorker();

            // define the event handlers
            bw.DoWork += (sender, args) =>
            {
                Console.WriteLine("START Thread-------------");
                Console.WriteLine("Print:" + i);
            };
            bw.RunWorkerCompleted += (sender, args) =>
            {
                Console.WriteLine("END Thread-------------");
                if (args.Error != null)
                {
                    Console.WriteLine(args.Error.ToString());
                }
            };

            bw.RunWorkerAsync(); // starts the
        }
    }

它将在控制台中显示:

START PROGRAMN-----------------------------------
END PROGRAMN-----------------------------------
START Thread-------------
Print:0
END Thread-------------
START Thread-------------
Print:0
END Thread-------------

为什么第二次打印不显示打印1?

我认为第一次迭代是正确的,因为我看到print:0但是第二次为什么我看不到print:1?

为ANSER编辑

没有[ThreadStatic]

static void Main(string[] args)
    {
        Console.WriteLine("START PROGRAMN-----------------------------------");
        test();
        Console.WriteLine("END PROGRAMN-----------------------------------");
        Console.Read();
    }
    [ThreadStatic]
    private static int i;
    private static void test()
    {
        for (i = 0; i < 2; i++)
        {
            var bw = new BackgroundWorker();

            // define the event handlers
            bw.DoWork += (sender, args) =>
            {
                Console.WriteLine("START Thread-------------");
                Console.WriteLine("Print:" + i);
            };
            bw.RunWorkerCompleted += (sender, args) =>
            {
                Console.WriteLine("END Thread-------------");
                if (args.Error != null)
                {
                    Console.WriteLine(args.Error.ToString());
                }
            };

            bw.RunWorkerAsync(); // starts the
        }
    }

它将在控制台中显示:

START PROGRAMN-----------------------------------
END PROGRAMN-----------------------------------
START Thread-------------
Print:2
END Thread-------------
START Thread-------------
Print:2
END Thread-------------

为什么第一个pirnt不显示打印0和第二个打印1?

为什么要显示2?

3 个答案:

答案 0 :(得分:2)

我认为你在这里并不真正理解ThreadStatic属性。这意味着,根据定义,Indicates that the value of a static field is unique for every thread.这意味着该值对于主线程(您创建BackgroundWorkers的位置)和BackgroundWorkers是唯一的,它将始终具有i的默认值0。 / p>

答案 1 :(得分:1)

忘记ThreadStatic你没有正确使用它。在你的情况下,它不是你需要的。您试图绕过的问题是因为否则您的结果将获得最新值,因为DoEvent未在其已更改的第一个线程上启动。你最终会遇到竞争条件。您需要使用参数来获得变量的明确本地实例。最简单的方法就是更改你的代码

for (int i = 0; i < 2; i++)
{
     var bw = new BackgroundWorker();

     // define the event handlers
     bw.DoWork += (sender, args) =>
     {
          // get the argument
          var value = args.Argument.ToString();
          Console.WriteLine("START Thread-------------");
          Console.WriteLine("Print:" + value);
     };
     bw.RunWorkerCompleted += (sender, args) =>
     {
         Console.WriteLine("END Thread-------------");
         if (args.Error != null)
         {
             Console.WriteLine(args.Error.ToString());
         }
     };

     bw.RunWorkerAsync(i); // starts the thread with arguments
 }

答案 2 :(得分:0)

检查'Console.WriteLine(“打印:”+ i);'在lambda里面。 在for循环中,“Print:”+ i不会被评估和连接。它将出现在您的匿名方法中,并且只有在该方法运行时才会连接。

由于您的[ThreadStatic]属性,int i不在线程之间共享。 “每个执行线程都有一个单独的字段实例,并独立设置和获取该字段的值。如果在另一个线程上访问该字段,它将包含不同的值。”

int i将被实例化,你得到int默认值。