2

假设我有两个线程,线程 A 和线程 B。在 C# 中,当线程 A 将一个对象(称为对象 X)设置为一个值并且线程 B 出现并尝试在线程设置该对象时获取该对象时会发生什么一种?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# 中的变量实现的。

4

3 回答 3

3

C#会抛出异常吗

不,它可能不会。运行时中没有任何东西会自动检查这种情况并引发异常。

但是,此时设置的“值”可能会或可能不会处于有效状态,因此一旦使用结果,无论使用该值的任何内容都可能很容易引发异常。

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

任何一个都是可能的。根据“对象”的类型,B 也有可能收到处于无效状态的对象。

如果您知道多个线程将访问一个值,则应始终注意同步对您的属性的访问。同步有很多选项,从使用(相对)简单的lock语句到其他更复杂的同步选项(例如ReaderWriterLock/ ReaderWriterLockSlimMutexSemaphore等)。

于 2012-08-15T18:09:53.083 回答
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;
    }
}

不知道,试试看:)

于 2012-08-15T18:09:19.900 回答
0

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

PS:这就是.NET Framework 中有lockand的原因。mutex

于 2012-08-15T18:09:23.760 回答