Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: Igors от Ноябрь 29, 2014, 17:29



Название: Азы
Отправлено: Igors от Ноябрь 29, 2014, 17:29
Эта тема для тех кто не работал с "многопоточностью". Ничего страшного там нет, но некоторые вещи могут показаться ... ну, немного странными. Вот одна из них, самая простая
Код
C++ (Qt)
if (count > 0)
--count;
else
...
Этот код "непотокобезопасен", т.е. не будет корректно выполняться параллельно 2-мя и более нитками. Никаких крашей не будет, но значение count рано или поздно окажется неверным. Впрочем такие ошибки делают все и много раз, даже если знают об этом  :)


Название: Re: Азы
Отправлено: ammaximus от Ноябрь 29, 2014, 20:08
Имеется ввиду, что операция декремента не является атомарной.
Есть ли алгоритм, как определить, что участок потокобезопасен? Мой вариант:
1. Участок защищен мутексом.
2. Атомарность
- Участок состоит из одной атомарной операции.
- Участок состоит из нескольких независимых атомарных операций.
3. Только чтение
- Не используются глобальные переменные.
- Глобальные переменные используются только для чтения.
4. Локальные переменные реентрабельны.

Для потокобезопасности необходимо выполнение условия 1, либо условия 2 и 3 и 4.


Название: Re: Азы
Отправлено: Igors от Ноябрь 29, 2014, 20:53
Хоть один ответил (причем очень неплохо). Только давайте не спешить, для тех кто с этим не работал все не так уж очевидно

Имеется ввиду, что операция декремента не является атомарной.
Нет, хотя и это правильно. Такой код
Код
C++ (Qt)
--count;
Также "not thread-safe". Почему? Процессор исполняет декремент примерно так (псевдокод)

1) загрузить переменную count в регистр
2) отнять от содержимого регистра 1
3) сохранить регистр в переменной (ячейке памяти)

Между 1-2 и/или 2-3 ОС имеет право "вытеснить поток", т.е. передать управление др нитке которая может работать с тем же count. Пример

- count было 5. Загрузили 5 в регистр и тут ОС передал управление
- для др нитки count тоже 5, она взяла и уменьшила его, теперь в ячейке 4
- теперь ОС вернул упр-е первой нитке. Но в регистре-то 5, отняли 1, записали, в ячейке 4

Итог: 2 раза отнимали от 5 единицу, должно быть 3, но имеем 4.  Чтобы не размазывать каждый раз объяснения (типа кто там на регистре) говорят просто "операция не атомарна".  Объявление переменной атомарной страхует от этой проблемы, напр
Код
C++ (Qt)
QAtomicInt count(100);
 
...
--count;
 
Теперь если 100 раз отняли единичку,  count будет четко ноль, хоть отнимали в одной нитке, хоть в 10, хоть как

Однако изначальный пример
Код
C++ (Qt)
if (count > 0)
--count;
else
...
 
По-прежнему not thread-safe, объявление count как QAtomicInt не спасает