简体   繁体   English

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

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

I have 3 questions that I need help with. 我有3个需要帮助的问题。

  1. What are the correct objects/references to be passed as lock statement parameter? 作为lock语句参数传递的正确对象/引用是什么? I've seen a lot of sample codes and I noticed that the objects/references passed in could possibly be non related to the current class or any other class in the program as long as the access modifier static is non public? 我已经看到了许多示例代码,并且我注意到,只要访问修饰符static是非公开的,传入的对象/引用就可能与当前类或程序中的任何其他类无关。 Eg: 例如:

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

    It just doesn't make sense to me. 这对我来说毫无意义。

  2. I found a sample code in MSDN about multi threading that uses lock statements too. 我在MSDN中找到了有关使用lock语句的多线程的示例代码。 In the sample there are two try / catch blocks with the Monitor.Wait() within it. 在该示例中,有两个try / catch块,其中包含Monitor.Wait() If I understand the logic correctly, the readerFlag will forbid the program to ever enter the try / catch block at all. 如果我正确理解逻辑,则readerFlag将完全禁止程序进入try / catch块。
    The code is example 2 from here: 该代码是此处的示例2:
    http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx http://msdn.microsoft.com/zh-CN/library/aa645740(v=vs.71).aspx

  3. How do I run a thread that runs in the background as long as the Windows Form is active? 只要Windows窗体处于活动状态,如何运行在后台运行的线程?

How and what you lock on depends upon what you're doing. 锁定方式和锁定方式取决于您在做什么。

Let's say that you're working with a device of some kind - say a coffee maker. 假设您正在使用某种设备-例如咖啡壶。 You might have a class that looks like this: 您可能有一个类似于以下内容的类:

public CoffeeMaker {
    private IntPtr _coffeeHandle;
    private Object _lock = new Object();
}

In this case, you are protecting access to the _coffeeHandle - a pointer/handle to a real physical device, so this is pretty easy: 在这种情况下,您将保护对_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
    }
 }

So if I'm running a multithreaded app, I (probably) don't want to read the number of cups that are available while I'm dispensing (maybe it's a hardware error). 因此,如果我运行的是多线程应用程序,则(可能)我不想读取分配时可用的杯子数量(可能是硬件错误)。 By protecting accesses to the handle, I can ensure that. 通过保护对手柄的访问,我可以确保这一点。 Also, I can't be asked to dispense while I'm already dispensing - that would be bad, so that's protected too. 另外,在我已经点胶时也不会要求我点胶-那样不好,因此也受到保护。 Finally, I don't dispense unless I have enough coffee available and you notice that I don't use my public property to check that - this way the action of ensuring there's enough coffee and dispensing are tied together. 最后,除非我有足够的咖啡可用,否则我不会分配咖啡,您会注意到我使用我的公共财产进行核实-这样一来,确保有足够的咖啡量和分配咖啡量的操作就捆绑在一起了。 The magic word is atomic - they can't be cut apart without creating issues. 不可思议的词是原子性的-无法将它们切开而不造成问题。

You use a static object as a lock if you have one and only one instance of a resource that needs protecting. 如果您只有一个需要保护的资源实例,则可以使用静态对象作为锁。 Think, "do I have a singleton?" 想一想,“我有一个单身人士吗?” and that will be a guideline for when you might need a static lock. 这将是您何时需要静态锁的指南。 For example, let's say that CoffeeMaker has a private constructor. 例如,假设CoffeeMaker具有私有构造函数。 Instead, you have a factory method that constructs coffee machines: 相反,您有一个构造咖啡机的工厂方法:

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);
    }
 }

Now in this case, it feels like CoffeeMaker should implement IDisposable so that handle gets taken care of, because if you don't release it then somebody might not be getting their coffee. 现在,在这种情况下,感觉CoffeeMaker应该实现IDisposable以便处理句柄,因为如果不释放它,则可能有人无法获得其咖啡。

There are a few problems though - maybe if there's not enough coffee, we should make more - and that takes a long time. 虽然有一些问题-也许如果咖啡不足,我们应该多做些-这需要很长时间。 Heck - dispensing coffee takes a long time, which is why we're careful to protect our resources. 哎呀-分配咖啡需要很长时间,这就是为什么我们要谨慎保护资源。 Now you're thinking that really all this coffee maker stuff should be in a thread of its own and that there should be an event that gets fired when the coffee is done, and then it starts to get complicated and you understand the importance of knowing what you're locking on and when so that you don't block making coffee because you asked how many cups are there. 现在您正在考虑,实际上所有这些咖啡壶中的东西都应该在其自己的线程中,并且应该有一个事件在完成咖啡后触发,然后它开始变得复杂,并且您了解了解的重要性您要锁定什么以及什么时候锁定,以免因为您询问有多少杯而阻止煮咖啡。

And if the words "deadlock", "atomic", "monitor", "wait", and "pulse" all sound foreign to you, you should consider reading up on multiprocessing/multithreading in general and see if you can solve the fair barbershop problem or the dining philosophers problem , both quintessential examples of resource contention. 如果您对“死锁”,“原子”,“监视器”,“等待”和“脉冲”一词听起来陌生,则应该考虑阅读多处理/多线程的一般知识,看看是否可以解决公平的理发店问题餐饮哲学家问题 ,都是资源争夺的典型例子。

1) your code is incomplete. 1)您的代码不完整。 You always lock around a certain (shared) resource. 您始终锁定某个(共享)资源。 The anyObject should have a close 1-1 correspondence in lifetime with that shared object. anyObject与该共享库的生命周期应具有接近1-1的对应关系。

For instance: 例如:

a) the simple but most direct pattern: a)简单但最直接的模式:

List<MyClass> sharedList = ...;
...
lock (sharedList) { sharedList.Add(item); }

there is a drawback in this pattern: what if other code also locks on sharedList for other reasons? 这种模式有一个缺点:如果其他代码由于其他原因也锁定了sharedList怎么办? Usually not a practical problem, but it is the reason that the recommended pattern is (b): 通常这不是一个实际问题,但这是推荐的模式为(b)的原因:

List<MyClass> sharedList = ...;
private object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }

Or, when the shared object is static (c) : 或者,当共享库为静态(c)时:

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

2) The threads alternate setting readerFlag to true or false so the try/catch blocks will be entered. 2)线程交替将readerFlag设置为true或false,因此将输入try / catch块。 The synchronization is done with Monitor.Pulse() and .Wait(). 同步是通过Monitor.Pulse()和.Wait()完成的。 Note that Wait() will yield the lock for the duration s there is no deadlock. 注意,Wait()将在持续时间s内产生锁定,没有死锁。

1: the object you use defines / is-defined-by the lock granularity you are trying to enforce. 1:您使用的对象根据您要强制执行的锁定粒度进行定义/定义。 If is is "anything calling against the current instance", then a private readonly object syncLock = new object() would be reasonable. 如果is是“任何针对当前实例的调用”,则private readonly object syncLock = new object()将是合理的。 If it is "any code, regardless of the instance" (static, in particular), then private readonly static object syncLock = new object() . 如果它是“任何代码,无论实例如何”(尤其是静态的),则private readonly static object syncLock = new object() Sometimes there is an obvious "thing" you are trying to protect that will also serve: a list, a queue, etc. The main wrong decisions are: this , typeof(...) , any string , any value-type that you are boxing for each lock , and anything that you have leaked outside of the instance. 有时,您尝试保护的显而易见的“事物”也将起作用:列表,队列等。主要的错误决策是: thistypeof(...) ,任何string ,任何值类型对每个lock以及您在实例外部泄漏的所有东西进行装箱。

2: Monitor.Wait releases the locks from the current thread, waiting for either a "pulse" or a timeout, at which point it wakes up and joins the queue to regain to locks it had (note the "s" there is for re-entrancy). 2: Monitor.Wait从当前线程释放锁,等待“脉冲”或超时,这时它将唤醒并加入队列以重新获得其拥有的锁(请注意,存在“ s” -入口)。 That means that two threads can use a Monitor to signal between themselves, by pulsing and waiting. 这意味着两个线程可以使用Monitor通过脉冲和等待在它们之间发出信号

3: unrelated; 3:无关; but basically "check a flag periodically, and when being pulsed" 但基本上是“定期检查标记,并在被脉冲时检查”

According the MSDN documentation : 根据MSDN文档

The argument provided to the lock keyword ... is used to define the scope of the lock. 提供给lock关键字...的参数用于定义锁的范围。 ...Strictly speaking, the object provided is used solely to uniquely identify the resource being shared among multiple threads, so it can be an arbitrary class instance. ...严格来说,提供的对象仅用于唯一标识多个线程之间共享的资源,因此它可以是任意的类实例。 In practice, however, this object usually represents the resource for which thread synchronization is necessary. 但是,实际上,该对象通常表示需要进行线程同步的资源。

In my case, I have passed the exact static object that I have needed to change. 就我而言,我已经传递了需要更改的确切静态对象。

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

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