Страницы

Поиск по вопросам

воскресенье, 2 февраля 2020 г.

Потокобезопасная коллекция с#

#c_sharp #lock


Привет. Искал инфу про потокобезопасную коллекцию и почти везде такой код:

Добавление в коллекцию

public void Add(int value)
{
    lock(sync)
    {         
        Add(value);
    }
}


тут sync это

private object sync = new object();


Я вставил себе.

public void Add(TkeyId keyId, TkeyName keyName, Tvalue value)
{
    lock(sync)
    {
        if (this.Where(g => g.Key.Name.Equals(keyName) && g.Key.Id.Equals(keyId)).Count() > 0)
            return;
        this.Add(new UserKey(keyId, keyName), value);
    }
}


Так вот вопрос в чем прикол.Как он блокирует за счет чего.
Простым языком объясните
    


Ответы

Ответ 1



Конструкция lock гарантирует следующее: два блока lock (p) { // тут содержимое блока } бегущие в разных потоках, никогда не будут выполнены одновременно, если объект p один и тот же.* Если один поток находится внутри lock, то другой будет ждать окончания выполнения этого блока. В этом и состоит суть блокировки. Как именно технически это реализуется, не так уж и важно. В C# lock вызывает конструкцию Monitor.Enter, а она, в свою очередь, внутри кода BCL реализует функциональность, подобную CRITICAL_SECTION самостоятельно, используя короткий холостой цикл (spin wait) и системные примитивы синхронизации. На других системах, разумеется, используются другие синхронизационные функции ОС. Как именно работают эти функции — внутренняя подробность устройства ОС (завязанная, надо думать, на системный планировщик потоков). Главное — знать, что внутрь lock'а на один и тот же объект два потока проникнуть не могут. *Также она гарантирует нужные memory barrier'ы для многопоточного сценария, но это неважно в контексте данного обсуждения.

Ответ 2



Оператор lock (sync) { ... } будет транслирован в следующую конструкцию (.NET >= 4): // Флаг успешной блокировки bool acquiredLock = false; try { // Захватываем блокировку для sync Monitor.Enter(lockObject, ref acquiredLock); // Потокобезопасный код } finally { // Освобождаем блокировку для sync если блокировка была выполнена if (acquiredLock) { Monitor.Exit(lockObject); } } Когда потоком вызывается метод Monitor.Enter то участок кода будет заблокирован для доступа других потоков, вплоть до того момента, когда поток не вызовет метод Monitor.Exit.

Комментариев нет:

Отправить комментарий