[英]C# lock statement, what object to lock on?
我有3个需要帮助的问题。
作为lock
语句参数传递的正确对象/引用是什么? 我已经看到了许多示例代码,并且我注意到,只要访问修饰符static
是非公开的,传入的对象/引用就可能与当前类或程序中的任何其他类无关。 例如:
private Object anyObj = new Object(); lock(anyObj){.....} private static readonly object Locker = new object(); lock(Locker){.....}
这对我来说毫无意义。
我在MSDN中找到了有关使用lock
语句的多线程的示例代码。 在该示例中,有两个try
/ catch
块,其中包含Monitor.Wait()
。 如果我正确理解逻辑,则readerFlag
将完全禁止程序进入try
/ catch
块。
该代码是此处的示例2:
http://msdn.microsoft.com/zh-CN/library/aa645740(v=vs.71).aspx
只要Windows窗体处于活动状态,如何运行在后台运行的线程?
锁定方式和锁定方式取决于您在做什么。
假设您正在使用某种设备-例如咖啡壶。 您可能有一个类似于以下内容的类:
public CoffeeMaker {
private IntPtr _coffeeHandle;
private Object _lock = new Object();
}
在这种情况下,您将保护对_coffeeHandle的访问-指向实际物理设备的指针/句柄,因此这非常简单:
public int AvailableCups {
get {
lock (_lock) {
return GetAvailableCups(_coffeeHandle); // P/Invoked
}
}
}
public void Dispense(int nCups)
{
lock (_lock) {
int nAvail = GetAvailableCups(_coffeeHandle);
if (nAvail < nCups) throw new CoffeeException("not enough coffee.");
Dispense(_coffeeHandle, nCups); // P/Invoked
}
}
因此,如果我运行的是多线程应用程序,则(可能)我不想读取分配时可用的杯子数量(可能是硬件错误)。 通过保护对手柄的访问,我可以确保这一点。 另外,在我已经点胶时也不会要求我点胶-那样不好,因此也受到保护。 最后,除非我有足够的咖啡可用,否则我不会分配咖啡,您会注意到我不使用我的公共财产进行核实-这样一来,确保有足够的咖啡量和分配咖啡量的操作就捆绑在一起了。 不可思议的词是原子性的-无法将它们切开而不造成问题。
如果您只有一个需要保护的资源实例,则可以使用静态对象作为锁。 想一想,“我有一个单身人士吗?” 这将是您何时需要静态锁的指南。 例如,假设CoffeeMaker具有私有构造函数。 相反,您有一个构造咖啡机的工厂方法:
static Object _factLock = new Object();
private CoffeeMaker(IntPtr handle) { _coffeeHandle = handle; }
public static CoffeeMaker GetCoffeeMaker()
{
lock (_factLock) {
IntPtr _handle = GetCoffeeMakerHandle(); // P/Invoked
if (_handle == IntPtr.Zero) return null;
return new CoffeeMaker(_handle);
}
}
现在,在这种情况下,感觉CoffeeMaker应该实现IDisposable以便处理句柄,因为如果不释放它,则可能有人无法获得其咖啡。
虽然有一些问题-也许如果咖啡不足,我们应该多做些-这需要很长时间。 哎呀-分配咖啡需要很长时间,这就是为什么我们要谨慎保护资源。 现在您正在考虑,实际上所有这些咖啡壶中的东西都应该在其自己的线程中,并且应该有一个事件在完成咖啡后触发,然后它开始变得复杂,并且您了解了解的重要性您要锁定什么以及什么时候锁定,以免因为您询问有多少杯而阻止煮咖啡。
如果您对“死锁”,“原子”,“监视器”,“等待”和“脉冲”一词听起来陌生,则应该考虑阅读多处理/多线程的一般知识,看看是否可以解决公平的理发店问题或餐饮哲学家问题 ,都是资源争夺的典型例子。
1)您的代码不完整。 您始终锁定某个(共享)资源。 anyObject
与该共享库的生命周期应具有接近1-1的对应关系。
例如:
a)简单但最直接的模式:
List<MyClass> sharedList = ...;
...
lock (sharedList) { sharedList.Add(item); }
这种模式有一个缺点:如果其他代码由于其他原因也锁定了sharedList
怎么办? 通常这不是一个实际问题,但这是推荐的模式为(b)的原因:
List<MyClass> sharedList = ...;
private object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }
或者,当共享库为静态(c)时:
static List<MyClass> sharedList = ...;
private static object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }
2)线程交替将readerFlag
设置为true或false,因此将输入try / catch块。 同步是通过Monitor.Pulse()和.Wait()完成的。 注意,Wait()将在持续时间s内产生锁定,没有死锁。
1:您使用的对象根据您要强制执行的锁定粒度进行定义/定义。 如果is是“任何针对当前实例的调用”,则private readonly object syncLock = new object()
将是合理的。 如果它是“任何代码,无论实例如何”(尤其是静态的),则private readonly static object syncLock = new object()
。 有时,您尝试保护的显而易见的“事物”也将起作用:列表,队列等。主要的错误决策是: this
, typeof(...)
,任何string
,任何值类型对每个lock
以及您在实例外部泄漏的所有东西进行装箱。
2: Monitor.Wait
从当前线程释放锁,等待“脉冲”或超时,这时它将唤醒并加入队列以重新获得其拥有的锁(请注意,存在“ s” -入口)。 这意味着两个线程可以使用Monitor
通过脉冲和等待在它们之间发出信号 。
3:无关; 但基本上是“定期检查标记,并在被脉冲时检查”
根据MSDN文档 :
提供给lock关键字...的参数用于定义锁的范围。 ...严格来说,提供的对象仅用于唯一标识多个线程之间共享的资源,因此它可以是任意的类实例。 但是,实际上,该对象通常表示需要进行线程同步的资源。
就我而言,我已经传递了需要更改的确切静态对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.