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

本文关键字:为什么不 增加 线程 | 更新日期: 2023-09-27 18:17:24

我不明白为什么用这段代码

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?

EDIT FOR answer

没有[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-------------

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

为什么显示2?

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

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

忘掉你没有正确使用的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
 }

检查你的控制台。WriteLine("Print:" + i);'在lambda内部。在for循环内,"Print:"+ i不会被计算和连接。它将出现在您的匿名方法中,并且仅在该方法运行时才会被连接。

因为你的[ThreadStatic]属性,int i不能在线程间共享。每个正在执行的线程都有一个单独的字段实例,并独立地设置和获取该字段的值。如果在不同的线程上访问该字段,它将包含不同的值。"

int I将被实例化,您将获得int的默认值