【问题标题】:Threading in c# with locksc# 中带锁的线程
【发布时间】:2016-11-11 19:12:18
【问题描述】:

我想我在这里遗漏了一些基础知识并且无法解决问题..

以下程序的输出与预期不符。有人可以帮我理解这里的问题吗?

using System;
using System.Threading;

public class Program
{
    private static readonly object _lock = new object();
    public static void Main()
    {
        for (var i = 0; i < 10; i++)
        {
            //Console.WriteLine("Start "+i); 
            System.Threading.Thread thread = new System.Threading.Thread(() => ExecuteInBackground(i));
            thread.IsBackground = true;
            thread.Start();
        }
    }

    private static void ExecuteInBackground(Object obj)
    {
        lock (_lock)
        {
            Console.WriteLine("A "+obj);
            test.ttt(obj);
        }
    }
}


public static class test
{
    public static void ttt(object obj)
    {
        Console.WriteLine("B "+ obj);
    }
}

我希望在输出中看到 0 到 9.. 但实际输出如下..

A 1
B 1
A 1
B 1
A 3
B 3
A 4
B 4
A 5
B 5
A 6
B 6
A 7
B 7
A 8
B 8
A 9
B 9
A 10
B 10

非常感谢任何帮助。

请随意使用https://dotnetfiddle.net/nYfbMU中的代码

谢谢, 雷迪。

【问题讨论】:

    标签: c# multithreading locking


    【解决方案1】:

    改变这个:

    for (var i = 0; i < 10; i++)
    {
        //Console.WriteLine("Start "+i); 
        System.Threading.Thread thread = new System.Threading.Thread(() => ExecuteInBackground(i));
    

    到这里:

    for (var i = 0; i < 10; i++)
    {
        var temp = i;
        //Console.WriteLine("Start "+i); 
        System.Threading.Thread thread = new System.Threading.Thread(() => ExecuteInBackground(temp));
    

    这是一个关闭问题。见Why is it bad to use an iteration variable in a lambda expression

    原始代码没有按预期工作的原因以及 temp 变量的原因是因为 () =&gt; ExecuteInBackground(i) 就像在说“在未来的某个时候,我希望这个新线程调用 ExecuteInBackground方法,传入任何值我有调用时“。由于循环变量在循环开始时进入范围,而在循环结束后超出范围,因此 i 的值在您调用 Thread 和 ExecuteInBackground 执行之间发生变化。通过在循环内使用临时变量,每次循环迭代都会超出范围,每个线程对 ExecuteInBackground 的调用本质上是在每次调用时获得一个具有不变值的不同变量,并且 i 的下一次递增不会混乱事情发生了。

    【讨论】:

    • 它按预期工作.. 但在读取时,我将几个对象传递给异步函数.. 它是如何工作的..?
    • @Reddy - 我不明白你的问题。您是在问为什么 temp 变量有效吗?
    • 是的。我的问题是如何将对象(通过 ref 传递)传递给异步函数?
    • 以下是对我有用的解决方案.. 谢谢你的帮助.. @hatchet
    • 是的,这也可以,因为您对fn 的调用传递了 i 的值(因为 int 是一个结构),并且您的 lambda 表达式的闭包问题不再是问题。
    【解决方案2】:

    这对我有用..

    using System;
    using System.Threading;
    
    public class Program
    {
        private static readonly object _lock = new object();
        public static void Main()
        {
            for (var i = 0; i <= 10; i++)
            {
                fn(i);
            }
            Console.ReadLine();
        }
    
        private static void fn(int i)
        {
            System.Threading.Thread thread = new System.Threading.Thread(() => ExecuteInBackground(i));
            thread.IsBackground = true;
            thread.Start();
        }
    
        private static void ExecuteInBackground(Object obj)
        {
            lock (_lock)
            {
                Thread.Sleep(500);
                Console.WriteLine("A "+obj);
                test.ttt(obj);
            }
        }
    }
    public static class test
    {
        //private static readonly object _lock = new object();
        public static void ttt(object obj)
        {
            //lock(_lock)
                Console.WriteLine("B "+ obj);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 2019-04-04
      相关资源
      最近更新 更多