C#Getter-Setter比赛条件

时间:2012-08-15 18:00:51

标签: c# multithreading exception runtime race-condition

假设我有两个线程,线程A和线程B.当线程A设置一个对象,将其称为对象X,一个值,并且线程B出现并尝试获取该对象时,C#中会发生什么?由线程A设置? C#会抛出异常,B会在A对其进行更改之前接收对象X,还是B会在A对其进行更改后接收对象X?

我认为很清楚,但这里是代码(即使添加了同步,我仍然不能100%确定这会导致我上面提到的确切情况发生):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication8 {
    public partial class Form1 : Form {
        private AutoResetEvent waitEvent = new AutoResetEvent(false);
        int objectX = 0;

        public Form1() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {
            DateTime startTime = DateTime.Now;
            Console.WriteLine("---------------------------- START @ " + startTime + " ----------------------------------------------------------------------");
            Thread A = new Thread(ThreadAWorkMethod);
            Thread B = new Thread(ThreadBWorkMethod);
            objectX = 0;
            waitEvent = new AutoResetEvent(false);
            A.Start();
            B.Start();
            A.Join();
            B.Join();
            Console.WriteLine("---------------------------- FINISHED AFTER " + (DateTime.Now - startTime).TotalMilliseconds + " ----------------------------");
        }

        public void ThreadAWorkMethod() {
            waitEvent.WaitOne();
            objectX = 5;
            Console.WriteLine("Value has been changed to: " + objectX + " in thread A at " + DateTime.Now);
            return;
        }

        public void ThreadBWorkMethod() {
            waitEvent.Set();
            string xInThreadB = objectX.ToString();
            Console.WriteLine("Value in thread B: " + xInThreadB + " at " + DateTime.Now);
            return;
        }
    }
}

线程B到控制台的输出看起来是0或5,但即使是通过检查DateTime也不能确定哪个线程首先得到服务,因为两个线程将具有相同的时间戳...和一个输出总是首先进入控制台,所以说谁首先得到服务,如果线程实际上在一个get-set上碰撞。因此,最终看起来像某些人提到的那样,从较低的框架级别对C#中的变量实现了锁定。

3 个答案:

答案 0 :(得分:3)

  

C#会抛出异常

不,可能不会。运行时中没有任何内容可以自动检查此情况并引发异常。

但是,设置的“值”在此时可能处于有效状态,也可能不处于有效状态,因此只要结果使用,无论使用什么值,都可能轻易引发异常。

  

B会在A对其进行更改之前接收对象X,还是B在A对其进行更改后接收对象X?

要么可以。根据“对象”的类型,B也可能会以无效状态接收对象。

如果您知道多个线程将访问某个值,则应始终注意同步对您的属性的访问权限。有许多同步选项,从使用(相对)简单的lock statement到其他更复杂的同步选项(例如ReaderWriterLock / ReaderWriterLockSlimMutex,{{1}等等)。

答案 1 :(得分:1)

那么,这样的事情呢?

public class Test
{
    public Test()
    {
        DateTime now = DateTime.Now;
        Debug.WriteLine("Test started.");
        A.Start();
        B.Start();
        A.Join();
        B.Join();
        Debug.WriteLine("Total time, in milliseconds, that you just spent in order to save StackOverflow members several minutes of their time: " + (DateTime.Now - now).TotalMilliseconds + " :)");
    }

    int objectX = 0;

    Thread A = new Thread(ThreadAWorkMethod);
    Thread B = new Thread(ThreadBWorkMethod);

    public void ThreadAWorkMethod()
    {
        objectX = 5;
        Debug.WriteLine("Value has been changed to: " + objectX.ToString() + "at " DateTime.Now.Milliseconds);
        return;
    }
    public void ThreadBWorkMethod()
    {
        string xInThreadB = objectX.ToString();
        Debug.WriteLine("Value in thread b: " + xInThreadB + "at " DateTime.Now.Milliseconds);
        return;
    }
}

我不知道,试一试:)

答案 2 :(得分:0)

可能与C# Threading: a race condition example类似的问题。

PS:这就是.NET Framework中存在lockmutex的原因。