繁体   English   中英

C#锁定语句,要锁定的对象是什么?

[英]C# lock statement, what object to lock on?

我有3个需要帮助的问题。

  1. 作为lock语句参数传递的正确对象/引用是什么? 我已经看到了许多示例代码,并且我注意到,只要访问修饰符static是非公开的,传入的对象/引用就可能与当前类或程序中的任何其他类无关。 例如:

     private Object anyObj = new Object(); lock(anyObj){.....} private static readonly object Locker = new object(); lock(Locker){.....} 

    这对我来说毫无意义。

  2. 我在MSDN中找到了有关使用lock语句的多线程的示例代码。 在该示例中,有两个try / catch块,其中包含Monitor.Wait() 如果我正确理解逻辑,则readerFlag将完全禁止程序进入try / catch块。
    该代码是此处的示例2:
    http://msdn.microsoft.com/zh-CN/library/aa645740(v=vs.71).aspx

  3. 只要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() 有时,您尝试保护的显而易见的“事物”也将起作用:列表,队列等。主要的错误决策是: thistypeof(...) ,任何string ,任何值类型对每个lock以及您在实例外部泄漏的所有东西进行装箱。

2: Monitor.Wait从当前线程释放锁,等待“脉冲”或超时,这时它将唤醒并加入队列以重新获得其拥有的锁(请注意,存在“ s” -入口)。 这意味着两个线程可以使用Monitor通过脉冲和等待在它们之间发出信号

3:无关; 但基本上是“定期检查标记,并在被脉冲时检查”

根据MSDN文档

提供给lock关键字...的参数用于定义锁的范围。 ...严格来说,提供的对象仅用于唯一标识多个线程之间共享的资源,因此它可以是任意的类实例。 但是,实际上,该对象通常表示需要进行线程同步的资源。

就我而言,我已经传递了需要更改的确切静态对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM