C# 线程 - 锁定对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1287356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# threading - Lock Object
提问by paul simmons
I am trying to lock a "boxed" object in a c# app, is this not possible?
我试图在 ac# 应用程序中锁定一个“装箱”对象,这不可能吗?
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);
}
}
}
}
}
In another class I can start 2 threads:
在另一堂课中,我可以启动 2 个线程:
Thread b1 = new Thread(new ThreadStart(t1.w));
b1.Start();
Thread b2 = new Thread(new ThreadStart(t1.w));
b2.Start();
However the portion is not locked. When I lock an arbitrary object (i.e. one created and not modified as object a=new object()) it locks well. Is boxing operation somehow "depromotes" my Object??
但是,该部分未锁定。当我锁定一个任意对象(即一个创建但未修改为对象 a=new object())时,它锁定得很好。拳击操作是否以某种方式“降低”了我的对象?
采纳答案by AgileJon
You need to create a separate lock object. The problem is that you re-assign t_x inside the loop. Assuming thread b1 gets inside the loop before b2 gets to the lock statement, b2 will be allowed inside the lock statement because, by that time, t_x will be a new object that does not have a lock on it.
您需要创建一个单独的锁对象。问题是你在循环内重新分配了 t_x 。假设线程 b1 在 b2 进入 lock 语句之前进入循环,b2 将被允许在 lock 语句中,因为到那时, t_x 将是一个没有锁定的新对象。
回答by Lee
No, you can't do this - the lock block is shorthand for the following:
不,你不能这样做 - 锁块是以下内容的简写:
try(Monitor.Enter(lockObject))
{
//critical section
}
finally
{
Monitor.Exit(lockObject)
}
The documentation for Monitor.Enterstates, "Use Monitor to lock objects (that is, reference types), not value types. When you pass a value type variable to Enter, it is boxed as an object. If you pass the same variable to Enter again, it is boxed as a separate object, and the thread does not block"
Monitor.Enter的文档指出,“使用 Monitor 锁定对象(即引用类型),而不是值类型。当您将值类型变量传递给 Enter 时,它会被装箱为一个对象。如果您将相同的变量传递给再次进入,作为单独的对象装箱,线程不阻塞”
回答by Femaref
You have to use an extra object for the lock
您必须使用额外的对象来锁定
object lockObj = new object();
public void foo()
{
lock(lockObj)
{
//do stuff here
}
}
回答by CodingBarfield
The lock (t_x) call boxes an integer as a temporary object. Each call to lock(t_x) creates a New object and locking is useless.
锁 (t_x) 调用将整数装箱为临时对象。每次调用 lock(t_x) 都会创建一个 New 对象,而锁定是无用的。
(Lock expects an object and creates a NEW temporary object from the integer)
(锁定需要一个对象并从整数创建一个新的临时对象)
Just create a seperate lock object like said above by Femaref.
只需创建一个单独的锁对象,就像上面 Femaref 所说的那样。
回答by Toto
If you really want (need?) to lock on the object, you can use a kind of wrapper :
如果你真的想要(需要?)锁定对象,你可以使用一种包装器:
public class IntWrapper
{
public int Value{get;set;}
}
Or if you need to stay more abstract :
或者,如果您需要保持更抽象:
public class ObjectWrapper
{
public Object Value { get;set; }
}
回答by PeteGO
If you want to recognise when the data is loaded and also if the use tries to use it before then, you can do something like this:
如果您想识别数据何时加载以及用户是否在此之前尝试使用它,您可以执行以下操作:
Have a boolean flag like you mention, but use a separate object to lock before accessing it to prevent cross-thread race conditions.
有一个像你提到的布尔标志,但在访问它之前使用一个单独的对象来锁定它以防止跨线程竞争条件。
When the user tries to use the data, if it is not loaded (check the variable) you can add another event handler to the worker RunWorkerCompleted event, that will immediately do what the user wants when the data is loaded.
当用户尝试使用数据时,如果数据未加载(检查变量),您可以向 worker RunWorkerCompleted 事件添加另一个事件处理程序,当数据加载时,它将立即执行用户想要的操作。
Example:
例子:
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();
}
}