假设我有两个线程,线程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#中的变量实现了锁定。
答案 0 :(得分:3)
C#会抛出异常
不,可能不会。运行时中没有任何内容可以自动检查此情况并引发异常。
但是,设置的“值”在此时可能处于有效状态,也可能不处于有效状态,因此只要结果使用,无论使用什么值,都可能轻易引发异常。
B会在A对其进行更改之前接收对象X,还是B在A对其进行更改后接收对象X?
要么可以。根据“对象”的类型,B也可能会以无效状态接收对象。
如果您知道多个线程将访问某个值,则应始终注意同步对您的属性的访问权限。有许多同步选项,从使用(相对)简单的lock
statement到其他更复杂的同步选项(例如ReaderWriterLock
/ ReaderWriterLockSlim
,Mutex
,{{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中存在lock
和mutex
的原因。