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

use*_*498 54 c# multithreading locking

我有3个问题需要帮助.

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

    private Object anyObj = new Object();
    lock(anyObj){.....}
    
    private static readonly object Locker = new object();
    lock(Locker){.....}
    
    Run Code Online (Sandbox Code Playgroud)

    这对我来说没有意义.

  2. 我在MSDN中找到了一个关于使用lock语句的多线程的示例代码.在样本中有两个try/ catchMonitor.Wait().如果我正确理解逻辑,那么readerFlag将禁止程序进入try/ catchblock.
    代码是示例2从这里:http:
    //msdn.microsoft.com/en-us/library/aa645740(v = vs.71).aspx

  3. 只要Windows窗体处于活动状态,如何运行在后台运行的线程?

pli*_*nth 75

你如何以及如何锁定取决于你正在做什么.

假设您正在使用某种设备 - 比如咖啡机.您可能有一个如下所示的类:

public CoffeeMaker {
    private IntPtr _coffeeHandle;
    private Object _lock = new Object();
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您正在保护对_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
    }
 }
Run Code Online (Sandbox Code Playgroud)

因此,如果我正在运行多线程应用程序,我(可能)不想读取我在分配时可用的杯数(可能是硬件错误).通过保护对句柄的访问,我可以确保.另外,在我已经配药的时候,我不能被要求免除 - 这会很糟糕,所以它也受到了保护.最后,除非我有足够的咖啡,否则你不会放弃,而且你注意到我没有使用我的公共财产来检查 - 这样一来,确保咖啡和分配足够的作用就会被捆绑在一起.神奇的词是原子的 - 它们不能在不产生问题的情况下被分开.

如果您只有一个需要保护的资源实例,则使用静态对象作为锁.想想,"我有一个单身人士吗?" 这将是您何时需要静态锁定的指南.例如,假设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);
    }
 }
Run Code Online (Sandbox Code Playgroud)

现在在这种情况下,感觉CoffeeMaker应该实现IDisposable,以便处理句柄,因为如果你不释放它,那么有人可能没有得到他们的咖啡.

但是有一些问题 - 也许如果没有足够的咖啡,我们应该做更多 - 这需要很长时间.哎呀 - 分配咖啡需要很长时间,这就是为什么我们要小心保护我们的资源.现在你认为真的所有这些咖啡机的东西应该是自己的一个线程,并且应该有一个事件在咖啡完成后被解雇,然后它开始变得复杂,你明白了解知识的重要性什么你锁定什么,什么时候你不要阻止煮咖啡因为你问了多少杯.

如果"死锁","原子","监视器","等待"和"脉冲"这些词对你来说都很陌生,你应该考虑阅读一般的多处理/多线程,看看你是否可以解决这个公平的理发店问题餐饮哲学家问题,这两个都是资源争用的典型例子.

  • 这实际上是一个非常糟糕的例子.`IntPtr`是一个`struct`.作为一个值类型,如果你将它与`lock`一起使用,它就会被装箱.这意味着对`lock(_coffeeHandle)`的每次调用都会获得一个不同的对象实例,这意味着_zero_同步.不幸的是,这个答案(迄今为止)获得了最多的选票,因为它是最不实用/最有害的. (4认同)

Hen*_*man 35

1)您的代码不完整.您始终锁定某个(共享)资源.的anyObject应在与该共享对象寿命密切1-1的对应关系.

例如:

a)简单但最直接的模式:

List<MyClass> sharedList = ...;
...
lock (sharedList) { sharedList.Add(item); }
Run Code Online (Sandbox Code Playgroud)

这种模式有一个缺点:如果其他代码也sharedList因其他原因而锁定怎么办?通常不是一个实际问题,但这是推荐模式是(b)的原因:

List<MyClass> sharedList = ...;
private object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }
Run Code Online (Sandbox Code Playgroud)

或者,当共享对象是静态的时(c):

static List<MyClass> sharedList = ...;
private static object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }
Run Code Online (Sandbox Code Playgroud)

2)线程交替设置readerFlag为true或false,因此将输入try/catch块.使用Monitor.Pulse()和.Wait()完成同步.请注意,Wait()将在没有死锁的持续时间内产生锁定.

  • @Henk 关于第一个模式,即使其他代码锁定它,您也无法访问共享列表。但是,那是必需的东西。我对么 (2认同)

Mar*_*ell 6

1:您使用的对象由您尝试强制执行的锁定粒度定义/定义.如果是"任何调用当前实例的东西",那么a private readonly object syncLock = new object()是合理的.如果它是"任何代码,无论实例如何"(特别是静态的),那么private readonly static object syncLock = new object().有时候,有一个明显的"东西"你想保护也将成为:一个列表,队列等,主要错误的决定是:this,typeof(...),任何string,你是拳击每个任何value-type lock,以及任何你已经在实例外泄露了.

2:从当前线程Monitor.Wait 释放锁定,等待"脉冲"或超时,此时它会唤醒并加入队列以重新获得锁定(注意"s"表示重新进入) .这意味着两个线程可以使用a 通过脉冲和等待在它们之间Monitor发出信号.

3:无关; 但基本上"定期检查一个标志,并在脉冲时"