Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 12.11.20 13:19
Оценка: 1 (1) -1
Есть локальная переменная bool-типа, которую изменяет один поток а читает другой. Какие могут быть проблемы?

Пример:

class Program
    {
        static void Main(string[] args)
        {
            bool b = true;

            new Thread(() =>
            {
                Thread.Sleep(5000);
                b = false;
            }) {IsBackground = true}.Start();

            while (b)
            {
                Console.WriteLine("b=" + b);
                Thread.Sleep(1000);
            }

            Console.WriteLine("b=" + b);
        }
    }
Отредактировано 12.11.2020 19:48 Shmj . Предыдущая версия .
Re: Доступ к локальной переменной из разных потоков
От: vmpire Россия  
Дата: 12.11.20 14:11
Оценка: 1 (1) +5 -1
Здравствуйте, Shmj, Вы писали:

S>Есть локальная переменная bool-типа, которую изменяет один поток а читает другой. Какие могут быть проблемы?

Если переменная не volatile и нет лока вокруг, то чтение, вероятно, может быть соптимизировано и читающий поток не получит нового значения.
Отредактировано 12.11.2020 14:27 vmpire . Предыдущая версия .
Re: Доступ к локальной переменной из разных потоков
От: Pzz Россия https://github.com/alexpevzner
Дата: 12.11.20 14:17
Оценка: +5
Здравствуйте, Shmj, Вы писали:

S>Есть локальная переменная bool-типа, которую изменяет один поток а читает другой. Какие могут быть проблемы?


Большие.
Re: Доступ к локальной переменной из разных потоков
От: karbofos42 Россия  
Дата: 12.11.20 14:30
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Есть локальная переменная bool-типа, которую изменяет один поток а читает другой. Какие могут быть проблемы?


Могут быть проблемы, если будет код типа:
if (a != boolValue) // boolValue - та самая общая переменная
{
  a = boolValue; // к этому моменту уже значение boolValue может быть изменено другим потоком
{

дальше можно еще нафантазировать.
А иногда можно взять CancellationToken и не делать свой велосипед на булевом флаге для отмены операции, если для этого такая переменная нужна.
Re: Доступ к локальной переменной из разных потоков
От: Muxa  
Дата: 12.11.20 17:12
Оценка: -2
S>Есть локальная переменная bool-типа, которую изменяет один поток а читает другой. Какие могут быть проблемы?

Проблем быть не должно.
У каждого потока будет свой экземпляр этой переменной.
Re[2]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 12.11.20 19:49
Оценка:
Здравствуйте, vmpire, Вы писали:

V>Если переменная не volatile и нет лока вокруг, то чтение, вероятно, может быть соптимизировано и читающий поток не получит нового значения.


Локальная не может быть volatile.

Добавил пример — попробуйте продемонстрировать случай, когда возникает проблема.
Re[2]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 12.11.20 19:50
Оценка:
Здравствуйте, Pzz, Вы писали:

S>>Есть локальная переменная bool-типа, которую изменяет один поток а читает другой. Какие могут быть проблемы?


Pzz>Большие.


Добавил пример — продемонстрируйте проблему.
Re[2]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 12.11.20 19:50
Оценка:
Здравствуйте, karbofos42, Вы писали:

K>Могут быть проблемы, если будет код типа:

K>
K>if (a != boolValue) // boolValue - та самая общая переменная
K>{
K>  a = boolValue; // к этому моменту уже значение boolValue может быть изменено другим потоком
K>{
K>

K>дальше можно еще нафантазировать.
K>А иногда можно взять CancellationToken и не делать свой велосипед на булевом флаге для отмены операции, если для этого такая переменная нужна.

Дык... По условиям — только один потом может изменить значение. Второй только читает.
Re[2]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 12.11.20 19:51
Оценка:
Здравствуйте, Muxa, Вы писали:

M>Проблем быть не должно.

M>У каждого потока будет свой экземпляр этой переменной.

Если бы у каждого свой экземпляр — то второй поток не узнал бы, что первый изменил переменную. См. поясняющий пример.
Re[3]: Доступ к локальной переменной из разных потоков
От: vmpire Россия  
Дата: 12.11.20 20:05
Оценка: +6 -1
Здравствуйте, Shmj, Вы писали:

V>>Если переменная не volatile и нет лока вокруг, то чтение, вероятно, может быть соптимизировано и читающий поток не получит нового значения.

S>Локальная не может быть volatile.
S>Добавил пример — попробуйте продемонстрировать случай, когда возникает проблема.
В этом примере после компиляции переменная уже не будет локальной, это будет член класса, который сгенерируется из захваченной переменной.
В релизной компиляции всё будет зависеть от настроек компиляции и внутренней логики оптимизатора.
При компиляции наружного чтения переменной компилятор может и не догадаться, что переменная другого класса может меняться.
Пытаться демонстрировать случай я не буду, но я бы не стал рисковать, делая такую синхронизацию потоков.
Re[3]: Доступ к локальной переменной из разных потоков
От: karbofos42 Россия  
Дата: 12.11.20 20:08
Оценка: -1
Здравствуйте, Shmj, Вы писали:

S>Дык... По условиям — только один потом может изменить значение. Второй только читает.


Ну, второй и прочитал два раза и два раза получил разное значение.
К чему это приведёт — зависит от программы
Re[3]: Доступ к локальной переменной из разных потоков
От: karbofos42 Россия  
Дата: 12.11.20 20:15
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Локальная не может быть volatile.


Осталось разобраться как она так шарится между потоками

S>Добавил пример — попробуйте продемонстрировать случай, когда возникает проблема.


Для этого нужно знать как в итоге собираются лямбды.
Рекомендую скопировать код, например, в https://sharplab.io
Отредактировано 17.11.2020 14:38 VladD2 . Предыдущая версия .
Re[3]: Доступ к локальной переменной из разных потоков
От: Muxa  
Дата: 12.11.20 20:21
Оценка: +1
M>>Проблем быть не должно.
M>>У каждого потока будет свой экземпляр этой переменной.
S>См. поясняющий пример.

Это не локальная переменная относительно функций потоков.
Re[3]: Доступ к локальной переменной из разных потоков
От: Pzz Россия https://github.com/alexpevzner
Дата: 12.11.20 20:23
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Добавил пример — продемонстрируйте проблему.


Вплоть до переупорядочивания чтений/записей процессором (не компилятором, а именно процессором).

В твоем простом примере, конечно, такое вряд ли поймаешь — пока Sleep() отработает, все 100500 раз устаканится. Но в реальной жизни они будут, причем проявляться будут весьма неочевидным и невоспроизводимым образом.
Re[3]: Доступ к локальной переменной из разных потоков
От: Muxa  
Дата: 12.11.20 20:28
Оценка:
S>Добавил пример — попробуйте продемонстрировать случай, когда возникает проблема.

Например тут:
    public static int Main()
    {
        bool b = true;

        new Thread(() =>
        {
            Thread.Sleep(5);
            b = false;
        }) {IsBackground = true}.Start();

        while (b)
        {
            Console.WriteLine("b=" + b);
            Thread.Sleep(1);
        }

        Console.WriteLine("b=" + b);
        return 0;
    }
Re[4]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 12.11.20 20:50
Оценка:
Здравствуйте, Muxa, Вы писали:

M>Например тут:


И что за проблему вы увидели?
Re[5]: Доступ к локальной переменной из разных потоков
От: Muxa  
Дата: 13.11.20 03:41
Оценка:
M>>Например тут:

S>И что за проблему вы увидели?


Запусти несколько раз и увидишь как меняется вывод программы от запуска к запуску.
Re[4]: Доступ к локальной переменной из разных потоков
От: Mr.Delphist  
Дата: 13.11.20 07:56
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>В твоем простом примере, конечно, такое вряд ли поймаешь — пока Sleep() отработает, все 100500 раз устаканится. Но в реальной жизни они будут, причем проявляться будут весьма неочевидным и невоспроизводимым образом.


На прошлой неделе аккурат это самое огрёб, из-за материализации linq-последовательности другим потоком, нежели тот который порождает

Упрощённо как-то так:
var b = init-bool-here();
var ohShit = data.Select(d => create-something-from-bool-val(b));
b = next-bool-logic();

Task.Run(() => foreach(var sh in ohShit) {...});


Когда оно так в три строчки нарисовано — всё сразу понятно, но в реальном коде это было куда более многословно. Когда увидел причину — поржал над собой
Отредактировано 17.11.2020 14:43 VladD2 . Предыдущая версия .
Re[4]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 13.11.20 08:13
Оценка:
Здравствуйте, vmpire, Вы писали:

V>В этом примере после компиляции переменная уже не будет локальной, это будет член класса, который сгенерируется из захваченной переменной.

V>В релизной компиляции всё будет зависеть от настроек компиляции и внутренней логики оптимизатора.

Попробуйте вспомнить, откуда вы об этому узнали. Просто по слухам или где-то в авторитетных источниках прочитали?

Много раз слышал, но теперь начинаю сомневаться — может просто кто-то сказал и все за ним начали повторять.

В реальности ни разу не удалось продемонстрировать проблему.

V>При компиляции наружного чтения переменной компилятор может и не догадаться, что переменная другого класса может меняться.


И что? Создаст свою копию переменной, так что второй поток на нее влиять не будет?

V>Пытаться демонстрировать случай я не буду, но я бы не стал рисковать, делая такую синхронизацию потоков.


А причем тут синхронизация?
Re[4]: Доступ к локальной переменной из разных потоков
От: Shmj Ниоткуда  
Дата: 13.11.20 08:15
Оценка:
Здравствуйте, karbofos42, Вы писали:

K>Ну, второй и прочитал два раза и два раза получил разное значение.

K>К чему это приведёт — зависит от программы

Разное значение — т.к. второй поток изменил. Что странного?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.