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

252
24 августа 2017, 18:17

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

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

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<TkeyId, TkeyName>(keyId, keyName), value);
    }
}

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

Answer 1

Конструкция lock гарантирует следующее: два блока

lock (p)
{
    // тут содержимое блока
}

бегущие в разных потоках, никогда не будут выполнены одновременно, если объект p один и тот же.* Если один поток находится внутри lock, то другой будет ждать окончания выполнения этого блока. В этом и состоит суть блокировки.

Как именно технически это реализуется, не так уж и важно. В C# lock вызывает конструкцию Monitor.Enter, а она, в свою очередь, внутри кода BCL реализует функциональность, подобную CRITICAL_SECTION самостоятельно, используя короткий холостой цикл (spin wait) и системные примитивы синхронизации. На других системах, разумеется, используются другие синхронизационные функции ОС. Как именно работают эти функции — внутренняя подробность устройства ОС (завязанная, надо думать, на системный планировщик потоков).

Главное — знать, что внутрь lock'а на один и тот же объект два потока проникнуть не могут.

*Также она гарантирует нужные memory barrier'ы для многопоточного сценария, но это неважно в контексте данного обсуждения.

Answer 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.

READ ALSO
Создание View из Controller MVC

Создание View из Controller MVC

ASP занимаюсь недавно поэтому прошу сильно не битьЕсть небольшое приложение на asp MVC в котором нужно вывести на страничку некоторый список

245
Невозможность скрыть Label

Невозможность скрыть Label

Есть 3 лэйблы, 2 из который надо скрытьДелаю это не через XAML, почему не спрашивайте

201
.Net C# | Discord.Net v1.0.1 | Подключение к голосовому каналу

.Net C# | Discord.Net v1.0.1 | Подключение к голосовому каналу

После 20 секунд (примерно) от подключения бота к канал, он из него выходит, с сообщением: "Время ожидания операции истекло"

234