我想在c#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”我的对象??
答案 0 :(得分:23)
不,你不能这样做 - 锁定块是以下的简写:
try(Monitor.Enter(lockObject))
{
//critical section
}
finally
{
Monitor.Exit(lockObject)
}
documentation for Monitor.Enter状态,“使用Monitor来锁定对象(即引用类型),而不是值类型。当您将值类型变量传递给Enter时,它将被设置为对象。如果您通过了同一个变量再次输入,它被装箱为一个单独的对象,并且该线程不会阻止“
答案 1 :(得分:17)
您需要创建一个单独的锁定对象。问题是你在循环中重新分配t_x。假设线程b1在b2到达lock语句之前进入循环,则b2将被允许在lock语句中,因为到那时,t_x将是一个没有锁定的新对象。
答案 2 :(得分:2)
您必须使用额外的对象来锁定
object lockObj = new object();
public void foo()
{
lock(lockObj)
{
//do stuff here
}
}
答案 3 :(得分:2)
lock(t_x)调用将整数作为临时对象。每次调用lock(t_x)都会创建一个New对象,锁定也没用。
(Lock需要一个对象并从整数中创建一个新的临时对象)
只需像Femaref那样创建一个单独的锁定对象。
答案 4 :(得分:0)
如果你真的想(需要?)锁定对象,你可以使用一种包装器:
public class IntWrapper
{
public int Value{get;set;}
}
或者如果你需要更加抽象:
public class ObjectWrapper
{
public Object Value { get;set; }
}
答案 5 :(得分:0)
如果您想要识别加载数据的时间,以及在此之前用户是否尝试使用它,您可以执行以下操作:
有一个像你提到的布尔标志,但在访问它之前使用一个单独的对象来锁定,以防止跨线程竞争条件。
当用户尝试使用数据时,如果未加载(检查变量),则可以向工作者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();
}
}