Неожиданный результат при обращении двух потоков к глобальной переменной

#c# #multithreading #locking #global-variables

#c# #многопоточность #блокировка #глобальные переменные

Вопрос:

У меня есть два потока, t1 и t2.
Они оба выполняют операцию добавления к глобальной переменной с именем ‘count’, которая была инициализирована значением 0.
t1 выполняет count и t2 выполняет count =100 . Сначала я запускаю t1, затем t2, но результат на выходе не соответствует моим ожиданиям. Я что-то неправильно понимаю?

Это не поможет, даже если я использовал lock () в двух потоках.

Вот код C #:

 private int count = 0;
private object locker = new object();

void run()
{
    var t1 = new Thread(Add_1);
    var t2 = new Thread(Add_2);
    t1.Start();
    t2.Start();
}
  
 void Add_1()
{
    lock(locker)
    {
        count  ;
        Console.WriteLine(count);
    }
}

void Add_2()
{
    lock(locker)
    {
        count  = 100;
        Console.WriteLine(count);
    }
}
  

Иногда он выводит

1
101

или

100
101

Я не имею ни малейшего представления об этом. На мой взгляд, t1 должен иметь блокировку, пока не завершит свою работу. Но, похоже, у t2 есть шанс добавить количество раньше, чем у t1.

Надеюсь, кто-нибудь сможет мне помочь, спасибо.

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

1. Просто потому, что вы запускаете потоки в таком порядке, это не означает, что поток, запущенный первым, будет «победителем» в условиях блокировки.

2. Все lock гарантии a заключаются в том, что два потока не будут вводить блок кода, заблокированный заданной блокировкой ( locker ) одновременно. Итак, в этом отношении оба результата верны.

3. Is there I misunderstand something? — Да; Это не неожиданный результат, это именно ожидаемый результат, если вы хотите использовать разные потоки. Или, по крайней мере, это должен быть ожидаемый результат, если вы понимаете, что такое потоки и для чего они предназначены. Ваше ожидание было бы последовательным, а не асинхронным…

4. Каковы ваши ожидания?

5. @John действительно ценю ваш подробный ответ. Мне это очень помогает.

Ответ №1:

Что не так? На самом деле, порядок, который вы определяете или запускаете в своем коде, не указывает вашему компьютеру, как выполнять. Фактически, у вас есть два полностью разделенных потока, и ваша виртуальная машина / процессор может выполнять их в любом порядке. Блокировка не сообщает ему, каков правильный порядок выполнения, но только о том, что находится один поток, другие потоки должны ждать.

Итак, ваша программа работает нормально. Если вы хотите выполнить это по порядку, вам не нужны потоки, или вы можете использовать любой метод async / await для их синхронизации, или вы можете перевести один из них в спящий режим.

Может быть, вы хотите взглянуть на эти статьи