C#threading – 锁定对象

我想在ac#app中锁定一个“盒装”对象,这不可能吗?

class t { System.Object t_x = new object(); public t(int p) { t_x = p; } public void w() { lock (t_x) { for (int i = 0; i < 4; i++) { { t_x = ((int)t_x) + 1; Console.WriteLine(t_x); Thread.Sleep(1000); } } } } } 

在另一个类中,我可以开始2个线程:

  Thread b1 = new Thread(new ThreadStart(t1.w)); b1.Start(); Thread b2 = new Thread(new ThreadStart(t1.w)); b2.Start(); 

但是该部分未锁定。 当我锁定一个任意对象(即一个已创建但未被修改为对象a = new object())时,它会很好地锁定。 拳击操作不知何故“depromotes”我的对象?

您需要创建一个单独的锁对象。 问题是你在循环中重新分配t_x。 假设线程b1在b2到达lock语句之前进入循环,b2将被允许在lock语句中,因为到那时,t_x将是一个没有锁定的新对象。

不,你不能这样做 – 锁定块是以下的简写:

 try(Monitor.Enter(lockObject)) { //critical section } finally { Monitor.Exit(lockObject) } 

Monitor.Enter的文档指出,“使用Monitor来锁定对象(即引用类型),而不是值类型。当您将值类型变量传递给Enter时,它将被装箱为对象。如果您将相同的变量传递给再次输入,它被装箱为一个单独的对象,并且该线程不会阻止“

lock(t_x)调用将整数作为临时对象。 每次调用lock(t_x)都会创建一个New对象,而锁定则无用。

(Lock需要一个对象并从整数中创建一个新的临时对象)

只需像Femaref那样创建一个单独的锁定对象。

您必须使用额外的对象进行锁定

 object lockObj = new object(); public void foo() { lock(lockObj) { //do stuff here } } 

如果你真的想(需要?)锁定对象,你可以使用一种包装器:

 public class IntWrapper { public int Value{get;set;} } 

或者如果你需要保持更抽象:

 public class ObjectWrapper { public Object Value { get;set; } } 

如果您想要识别加载数据的时间,以及如果用户在此之前尝试使用它,您可以执行以下操作:

有一个像你提到的布尔标志,但在访问它之前使用一个单独的对象来锁定,以防止跨线程竞争条件。

当用户尝试使用数据时,如果未加载(检查变量),则可以向工作人员RunWorkerCompleted事件添加另一个事件处理程序,该事件将立即执行用户在加载数据时所需的内容。

例:

 public class MyClass { private bool dataIsReady = false; private object locker = new object(); BackgroundWorker worker; public void Begin() { worker = new BackgroundWorker(); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); } public void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { lock (locker) { dataIsReady = true; } } public void UseTriesToUseData() { lock (locker) { if (dataIsReady) { DoStuff(); } else { this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DoStuffCaller); } } } private void DoStuff() { // Do stuff with data. } private void DoStuffCaller(object sender, RunWorkerCompletedEventArgs e) { this.DoStuff(); } }