Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在多线程程序中未读取正确的属性值_C#_.net - Fatal编程技术网

C# 在多线程程序中未读取正确的属性值

C# 在多线程程序中未读取正确的属性值,c#,.net,C#,.net,我遇到了这样一种情况:我不确定为什么在多个线程中没有从属性中读取正确的属性值。。我已经编写了一个小的控制台应用程序来说明这种情况 class Program { private static Test MyObject; static void Main(string[] args) { MyObject = new Test(); Task.Run(() => { var obj = MyO

我遇到了这样一种情况:我不确定为什么在多个线程中没有从属性中读取正确的属性值。。我已经编写了一个小的控制台应用程序来说明这种情况

class Program
{
    private static Test MyObject;
    static void Main(string[] args)
    {
        MyObject = new Test();

        Task.Run(() =>
        {
            var obj = MyObject as Test;
            Console.WriteLine("1: " + obj.MyValue);
            Update("Thread1");
            Console.WriteLine("2: " + obj.MyValue);
        });
        Task.Run(() =>
        {
            var obj = MyObject as Test;
            Console.WriteLine("3: " + obj.MyValue);
            Thread.Sleep(100);
            Update("Thread2");
            Console.WriteLine("4: " + obj.MyValue);
        });

        void Update(string val)
        {
            lock (MyObject)
            {
                MyObject.MyValue = val;
            }
        }

        Thread.Sleep(400);
        Console.WriteLine("5: " + MyObject.MyValue);
    }
}

class Test
{
    public string MyValue { get; set; }
}
运行上面的行,我得到这个输出

1:
2: Thread1
3:
4: Thread2
5: Thread2
我的期望是“3:”应该总是说“3:Thread1”,因为同一个对象之前已经更新过。但事实并非如此,我不确定我在这里错过了什么。。。有人能解释一下吗

只是一张小纸条。。。如果您运行代码并得到不同的顺序,请重新运行它。。。我只对上面的顺序感兴趣。

有几件事:

  • 您的
    Update()
    方法将写入同步到
    MyValue
    属性,但对读取不做任何操作。因此,运行时可以自由地为对象使用缓存值。这不太可能与您观察到的输出有关,因为实际上您不太可能看到这一点,尤其是在x86硬件上。但是
  • 更重要的是,您的代码所展示的只是输出顺序可能会产生误导。
    控制台
    类具有同步功能,以确保多个线程的一致输出,但代码中没有任何内容可以确保如果输出行按特定顺序写入,则导致这些输出行的代码(例如读取
    MyValue
    属性)发生的顺序与这些输出行的显示顺序相同
  • 换句话说,仅仅因为控制台在
    “3:
    行之前显示了
    “2:
    行,这实际上并不意味着对
    更新(“Thread1”)
    的调用发生在对
    控制台.WriteLine(“3:+obj.MyValue”)的调用之前

    如果要确保输出行与程序中语句的执行顺序相匹配,还需要使用
    lock
    语句来保护各个操作

    更具体地,考虑以下代码的执行顺序:

    thread 1 thread 2 -------- -------- "value" parameter <= "3: " + obj.MyValue Console.WriteLine("1: " + obj.MyValue); Update("Thread1"); Console.WriteLine("2: " + obj.MyValue); Console.WriteLine(value);
    请注意,您需要在每次调用
    Console.WriteLine()
    时都使用该选项。这将确保写入控制台的任何值都是调用时属性的最新值。

    为什么您认为3应该说“Thread1”?它有效地与你的第一个线程同时运行,并且你在读取MyValue时没有相互排斥。你能更具体一点吗。。。“互斥”是什么意思?实例化引用
    MyObject
    的新
    obj
    实例的原因是什么?@RufusL:代码不会实例化新实例。它只是将对象引用复制到
    obj
    局部变量中。我同意这有点奇怪,但它应该对程序操作没有影响。@PeterDuniho是的,我想我的意思是“创建对同一实例的新引用”。我也不知道这会对程序产生什么影响,这就是为什么我想知道它的用途。你能给我看一个代码示例吗?根据你的观点,你会如何编写代码?
    lock (MyObject) Console.WriteLine("1: " + obj.MyValue);