programing

C # 잠금 문, 잠글 개체는 무엇입니까?

kingscode 2021. 1. 18. 08:11
반응형

C # 잠금 문, 잠글 개체는 무엇입니까?


도움이 필요한 3 가지 질문이 있습니다.

  1. lock명령문 매개 변수 로 전달되는 올바른 객체 / 참조는 무엇입니까 ? 많은 샘플 코드를 보았고 전달 된 객체 / 참조가 액세스 수정자가 static공용이 아닌 한 현재 클래스 또는 프로그램의 다른 클래스와 관련이 없을 수 있음을 알았습니다 . 예 :

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

    그것은 나에게 의미가 없습니다.

  2. lock을 사용하는 다중 스레딩에 대한 MSDN의 샘플 코드를 찾았 습니다. 샘플에는 두 개의 try/ catch블록이 Monitor.Wait()있습니다. 논리를 올바르게 이해하면 readerFlag프로그램이 try/ catch블록에 전혀 들어가는 것을 금지합니다 .
    코드는 여기에서 예제 2입니다 :
    http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx

  3. Windows Form이 활성화되어있는 동안 백그라운드에서 실행되는 스레드를 어떻게 실행합니까?


어떻게 그리고 무엇을 잠그는지는 당신이하는 일에 달려 있습니다.

어떤 종류의 장치 (예 : 커피 메이커)를 사용하고 있다고 가정 해 보겠습니다. 다음과 같은 클래스가있을 수 있습니다.

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구현 해야하는 것처럼 느껴집니다 . 왜냐하면 핸들을 놓지 않으면 누군가 커피를 얻지 못할 수 있기 때문입니다.

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. You always lock around a certain (shared) resource. The anyObject should have a close 1-1 correspondence in lifetime with that shared object.

For instance:

a) the simple but most direct pattern:

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? Usually not a practical problem, but it is the reason that the recommended pattern is (b):

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

Or, when the shared object is static (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. The synchronization is done with Monitor.Pulse() and .Wait(). Note that Wait() will yield the lock for the duration s there is no deadlock.


1: the object you use defines / is-defined-by the lock granularity you are trying to enforce. If is is "anything calling against the current instance", then a private readonly object syncLock = new object() would be reasonable. If it is "any code, regardless of the instance" (static, in particular), then 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.

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). That means that two threads can use a Monitor to signal between themselves, by pulsing and waiting.

3: unrelated; but basically "check a flag periodically, and when being pulsed"


According the MSDN documentation:

The argument provided to the lock keyword ... is used to define the scope of the 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.

ReferenceURL : https://stackoverflow.com/questions/13763917/c-sharp-lock-statement-what-object-to-lock-on

반응형