Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: Igors от Февраль 14, 2016, 10:06



Название: if (a == localA)
Отправлено: Igors от Февраль 14, 2016, 10:06
Код
C++ (Qt)
if (a == localA) {
// что-то делаем предполагая  ==
}
Этот участок кода НЕ защищен блокировками и может одновременно выполняться 2 или более нитками. Любая из них может менять переменную "a", переменная localA на стеке.

Можем ли мы опираться на рез-т такого сравнения?


Название: Re: if (a == localA)
Отправлено: Old от Февраль 14, 2016, 10:19
Без указания типа A вопрос бессмысленный, я оператор == могу определить как угодно.
И что значит опираться на результаты?


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 14, 2016, 10:34
Без указания типа A вопрос бессмысленный, я оператор == могу определить как угодно.
Если, по Вашему мнению, зависит от типа и/или оператора, то ответ "Иногда" - с примерчиками когда да, а когда нет

И что значит опираться на результаты?
Значит в плече if'а мы уверены что равенство остается истинным


Название: Re: if (a == localA)
Отправлено: Old от Февраль 14, 2016, 10:38
Значит в плече if'а мы уверены что равенство остается истинным
Конечно нет. В некоторых случаях мы можем быть уверены, что в момент проверки равенство истино.
Поэтому и усомнился в смысле опроса.


Название: Re: if (a == localA)
Отправлено: Akon от Февраль 14, 2016, 10:56
(a == localA) корректна, если:
1. Соответствующая ассемблерная инструкция будет атомарной (одной, а не состоять из нескольких). Если операнды не превышают используемого машинного слова, то инструкция будет атомарной. Например, для 32бит. кода все что меньше int (32 bit) дает одну инструкцию, а вот для int64 будет две инструкции. Я имею ввиду код для регистров общего назначения, SIMD-операнды (например, 256-битные) и в 32-х битном коде тоже будут атомарны.
2. a должна быть volatile.


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 14, 2016, 11:07
(a == localA) корректна, если:
Разумеется. Но вопрос был
Можем ли мы опираться на рез-т такого сравнения?
Т.е. речь идет о коде выполняемом в скобках if'a, который может быть достаточно (или сколь угодно) длинным


Название: Re: if (a == localA)
Отправлено: Bepec от Февраль 14, 2016, 12:17
неизвестны типы, неизвестны внешние условия, неизвестно может ли быть произведено удаление/замещение переменной. А так, если абстрагироваться от этих вещей, то уже ответили - при атомарной операции можем.


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 14, 2016, 12:40
неизвестны типы, неизвестны внешние условия, неизвестно может ли быть произведено удаление/замещение переменной. А так, если абстрагироваться от этих вещей, то уже ответили - при атомарной операции можем.
Что такое "удаление/замещение" переменной - хз :) О том что все нитки могут ее писать/читать сказано ясно. Опасаетесь какой-то ловушки с типом - хорошо, пусть тип 'а' просто int


Название: Re: if (a == localA)
Отправлено: Akon от Февраль 14, 2016, 12:56
Цитировать
Т.е. речь идет о коде выполняемом в скобках if'a, который может быть достаточно (или сколь угодно) длинным
?? абстрактный вопрос. А в чем принципиальная разница изменяется ли конкретной ниткой 'a' в 'if' блоке или где-то еще?

В общем случае нужна синхронизация. Грамотно она делается так (блокировка с двойной проверкой):
Код:
if (a == localA) {
  QMutexLocker(mutex);
  if (a == localA) {
   ....
    a = b;
  }
}


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 14, 2016, 13:18
?? абстрактный вопрос. А в чем принципиальная разница изменяется ли конкретной ниткой 'a' в 'if' блоке или где-то еще?
Не спрашивается где и как меняется "a", с блокировками или без. Речь идет об участке коде которому необходимо чтобы равенство оставалось истинным, иначе он развалится
// что-то делаем предполагая  ==

В общем случае нужна синхронизация. Грамотно она делается так (блокировка с двойной проверкой):
В условии сказано
Этот участок кода НЕ защищен блокировками

Да, неск лет назад Вы уже отвечали на почти такой же вопрос  :)


Название: Re: if (a == localA)
Отправлено: Bepec от Февраль 14, 2016, 13:37
удаление/замещение - это удаление переменной или изменение указателя, т.к. тип у вас хз какой.


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 14, 2016, 15:21
Хоть один ответил "нет" - вот это по-мужски, а то когда же возможно то самое "иногда" когда кусок кода работает просто по if'у, и ничего не боится ? 

удаление/замещение - это удаление переменной или изменение указателя, т.к. тип у вас хз какой.
А Вы бы не калякали, а слушали что умные люди говорят
Код
C++ (Qt)
if (index.isValid()) { ...
Без захвата мутекса это не будет работать верно в 2 нитках, т.к. вызов QModelIndex::isValid() никак не атомарный. Хоть это уясните


Название: Re: if (a == localA)
Отправлено: Old от Февраль 14, 2016, 15:25
Хоть один ответил "нет"
Ну так я вам в третьем посте это написал словами, а сейчас пришлось сделать выбор в опросе, что бы посмотреть результаты. :)
Другого результата я и не ожидал.


Название: Re: if (a == localA)
Отправлено: Old от Февраль 14, 2016, 15:30
Хоть один ответил "нет"
Но могу сделать "да", что-бы код выше стал корректным (с некоторыми условиями). :)


Название: Re: if (a == localA)
Отправлено: Bepec от Февраль 14, 2016, 17:19
Как печально Igors что вы не понимаете цимуса. Вы не подумали как index превратится в massiveRow[].
Наверно из него получим строку и столбец и после проверим есть ли такой элемент в массиве... Печально, не правда ли? И да, эти простейшие операции защищены мутексом в ф-ции data. Как же вы узко на мир глядите :)


Название: Re: if (a == localA)
Отправлено: Авварон от Февраль 14, 2016, 19:13
Как печально Igors что вы не понимаете цимуса. Вы не подумали как index превратится в massiveRow[].
Наверно из него получим строку и столбец и после проверим есть ли такой элемент в массиве... Печально, не правда ли? И да, эти простейшие операции защищены мутексом в ф-ции data. Как же вы узко на мир глядите :)

Код:
Thread B:
lock();
beginRemoveRows() -> signal
removeRows();
endRemoveRows() -> signal
unlock();

ThreadA
onBeginRemoveRows()
{
    int rowCount = model->rowCount(); /// упс, тут новый каунт, а вью ожидает старый, это же BEGIN removeRows, а они уже удалены.
}


Название: Re: if (a == localA)
Отправлено: Bepec от Февраль 14, 2016, 19:56
Ммм.. вы невнимательно читали. Защитить ВСЕ функции РАБОТАЮЩИЕ с КОНТЕЙНЕРОМ. Я их даже перечислил. rowCount, Data,RemoveRows,InsertRows.

В вашем случае нитка A встанет на мутексе rowCount, дождётся удаления и пойдёт дальше. Разве нет?

PS тут возможна иная ситуация - если будет повторный лок объекта внутри этих функций. Но мы же умные программисты и понимаем, что нужно опасаться выстрелов в ногу. Мы эти функции пишем, мы же за них и отвечаем.

PPS специально ради вас создал программку по вашему псевдокоду. 40 потоков выполняют код нитки Б, вылетов не замечено, конфликтов не замечено, передаваемый размер и фактический размер не разнятся.


Название: Re: if (a == localA)
Отправлено: Авварон от Февраль 14, 2016, 20:48
Ммм.. вы невнимательно читали. Защитить ВСЕ функции РАБОТАЮЩИЕ с КОНТЕЙНЕРОМ. Я их даже перечислил. rowCount, Data,RemoveRows,InsertRows.

В вашем случае нитка A встанет на мутексе rowCount, дождётся удаления и пойдёт дальше. Разве нет?

Встанет, но данные _уже_ будут изменены, так как событие было положено в очередь под мьютексом, потом этот мьютекс разблокировали, а потом событие получила вьюха и полезла в модель.
Если делать beginRemove через QueuedConnection, то мб будет работать.
А вот changePersistentIndexes может поломаться.

Ну то есть, еще раз:
Код:
Thread B:
beginRemoveRows() -> signal
removeRows();
endRemoveRows() -> signal

Как это видит Thread А:
removeRows();
beginRemoveRows()
endRemoveRows()


Название: Re: if (a == localA)
Отправлено: Bepec от Февраль 14, 2016, 21:46
Весь прикол, что thread A не видит removeRows, т.к. он не имеет к нему доступа, не имеет к нему указателя и не может никак на него воздействовать. RemoveRows значимо только для модели.

Пока не будет вызвано endRemoveRows никаких действий View совершено не будет.
В том и красота системы model-View. View, даже запрашивая самые невообразимые и чудовищные индексы, не вызывает никакой работы с данными, получая отлуп от модели.

Попробуйте ради прикола позапрашивать неадекватные данные из модели - у вас в результате выйдет обычный пшик. Сам шаблон блокирует такую ситуацию, что View может напортачить что то с данными. Вся работа с данными лежит только в модели. View лишь отображает, причём ему прощается абсолютно всё, начиная от запроса и до удаления неверных индексов.

PS верное отображение событий для Model/View
Код:
Model:
beginRemoveRows() -> signal
removeRows();
endRemoveRows() -> signal

Как это видит View:
beginRemoveRows()
endRemoveRows()
update()


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 15, 2016, 05:26
PPS специально ради вас создал программку по вашему псевдокоду. 40 потоков выполняют код нитки Б, вылетов не замечено, конфликтов не замечено, передаваемый размер и фактический размер не разнятся.
Так выкладывайте проект (вместо того чтобы воздух гонять)

Но могу сделать "да", что-бы код выше стал корректным (с некоторыми условиями). :)
Пожалуйста - можете вводить любые условия/правила, но участок кода первого поста должен работать без блокировок. 


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 15, 2016, 05:32
Если делать beginRemove через QueuedConnection, то мб будет работать.
А вот changePersistentIndexes может поломаться.
Нет никакой необходимости лезть в такие тонкости. Развалится paint, sizeHint и все-все что держит QModelIndex. Залатать все блокировками нереально - быстро приходит понимание что сам подход "дырявый". Ну а по поводу "проверок" в неблокируемом коде - этому и посвящен данный топик  :) 


Название: Re: if (a == localA)
Отправлено: Old от Февраль 15, 2016, 07:56
Пожалуйста - можете вводить любые условия/правила, но участок кода первого поста должен работать без блокировок. 
Что вы имеете ввиду, говоря "работать без блокировок"? Без применение средст синхронизации?


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 15, 2016, 08:25
Что вы имеете ввиду, говоря "работать без блокировок"? Без применение средст синхронизации?
Что имею то и введу :) "Участок кода" - это код начинающийся с if и заканчивающийся закрывающейся скобкой. т.е. все содержимое тега code первого поста. "Неблокируемый" - значит для его выполнения не нужны никакие мутексы и др средства синхронизации. Но в любых других местах (напр для установки "a") можно использовать все что угодно.


Название: Re: if (a == localA)
Отправлено: Old от Февраль 15, 2016, 09:01
Что имею то и введу :)
Лет 35 назад, по моему в первом классе, я слышал этот анекдот. Правда он меня не так сильно зацепил, как вас.

"Участок кода" - это код начинающийся с if и заканчивающийся закрывающейся скобкой. т.е. все содержимое тега code первого поста. "Неблокируемый" - значит для его выполнения не нужны никакие мутексы и др средства синхронизации. Но в любых других местах (напр для установки "a") можно использовать все что угодно.
Легко:
Код
C++ (Qt)
if( a == localA )
{
   int b;
   b++;
}
 

Пожалуйста.


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 15, 2016, 09:17
Легко:
Код
C++ (Qt)
if( a == localA )
{
   int b;
   b++;
}
 

Пожалуйста.
Наверное в первом классе Вы были тихим мальчиком, никого не трогали  :)


Название: Re: if (a == localA)
Отправлено: Old от Февраль 15, 2016, 09:49
Наверное в первом классе Вы были тихим мальчиком, никого не трогали  :)
Нет, умным.

Со своим желанием по пинать Вереса, вы традиционно забыли правильно сформулировать свои мысли. О чем я вам уже вторую страницу пытаюсь донести. Но... :)


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 15, 2016, 10:16
..вы традиционно забыли правильно сформулировать свои мысли.
Ну зачем, мягко говоря, "говорить неправду", причем систематически? Ведь это легко проверить, в первом посте ясно сказано, причем дважды
// что-то делаем предполагая  ==
...
Можем ли мы опираться на рез-т такого сравнения?
Хорошо, "еще раз"
Код
C++ (Qt)
if (a == localA) {
data.push_back(0); // мы уверены что доступ к контейнеру data сейчас безопасен
...
}
Хотя я прекрасно понимаю что это бесполезно, если уж человек включил "непонималку"...


Название: Re: if (a == localA)
Отправлено: Old от Февраль 15, 2016, 10:30
Хотя я прекрасно понимаю что это бесполезно, если уж человек включил "непонималку"...
Как раз не правда это. Я вам дал ответ в третьем посте этой темы. :)

А то, что вы не умеете формулировать свои мысли говорят ответы этой темы, например, ответ Akon.
Вы задали вопрос про сравнение, а ответ ждали про корректность кода в блоке после проверки.
Я это понял,  и начал задавать вам наводящие вопросы, а Akon не понял и начал отвечать про сравнение. Уверен не поняли и почти все остальные, кроме трех (меня, Авварон, Пантер) ответивших нет . :)


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 15, 2016, 13:46
Хорошо, подведем промежуточные итоги

Позиция 1: при параллельном выполнении само сравнение должно быть атомарным (см исчерпывающие пояснения Akon), иначе сразу до свидания. Правду сказать, я об этом даже не подумал когда создавал тему  :)

Позиция 2: но, как мы знаем, при параллельном выполнении возвращаемое значение означает лишь что "факт равенства имел место", т.е. это точно "было", но сейчас (когда выполняется следующая за if'oм) строка - это может быть уже не так. Ведь др нитка может успеть изменить значение "a", и с приветом

Все же мой ответ был "Иногда да". Конечно нитки должны менять "a" по определенным правилам (на то оно и "иногда"). Есть желающие построить такую конструкцию? Еще раз напомню - вне кода первого поста Вы можете использовать любые средства синхронизации. 


Название: Re: if (a == localA)
Отправлено: Bepec от Февраль 15, 2016, 17:23
Когда же до него дойдёт, что средства синхронизации специально созданы чтобы разруливать эту ситуацию.
И что любое решение данной проблемы сразу же будет занесено в список "средств синхронизации".


Название: Re: if (a == localA)
Отправлено: Old от Февраль 15, 2016, 18:32
Хорошо, подведем промежуточные итоги
Вы не правильно представляете итоги. Нет никаких позиций 1 и 2, это все одна и таже позиция.
Вы мыслите в каких-то строках программы, а на самом деле условие может измениться в той же самой строке. Т.е. и проверка и дальнейшее выполнение блока должно быть защищего какими-то средствами синхронизации.

Все же мой ответ был "Иногда да". Конечно нитки должны менять "a" по определенным правилам (на то оно и "иногда").
Как правильно написал Верес: не-не-не! никаких правил. Каждое правило это блокировка, в вашей терминологии.


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 16, 2016, 08:47
Рассмотрим похожий пример: "многопоточный" поиск максимума
Код
C++ (Qt)
if (theMaxA >  localA) {
// что-то делаем полагая >
}
 
Если текущий найденный максимум уже больше - то нечего и блокировки брать. Здесь внимание обычно сосредоточено на второй части, там примитивная ловушка
Код
C++ (Qt)
else  {
QMitexLocker lock(&mutex);
if (localA > theMaxA)    // вот ловушка, theMaxA мог измениться пока брали мутекс, нужно опять проверить
   theMaxA = localA;
}
При этом упускается из виду что if срабатывает всегда верно без блокировок, ну как бы "по алгоритму" или "по построению". Как то же самое сделать для == (вместо >)?   


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 18, 2016, 08:49
Как-то тихо стало :) Возможно подумали типа "ну там в каком-то конкретном алгоритме может и можно, но это сугубо частный случай". По аналогии с "поиском максимума". Все с точностью наоборот: сравнения >< только для арифметики и применимы, а вот равенство - случай весьма общий, от алгоритма практически не зависит. Даже Qt его использует  :)


Название: Re: if (a == localA)
Отправлено: Racheengel от Февраль 18, 2016, 10:17
Нет никакой гарантии, что компилятор будет настолько умным, что распознает поддержку многопоточности и сделает сравнение объектов атомарным. Поэтому лучше мутекс.


Название: Re: if (a == localA)
Отправлено: Igors от Февраль 19, 2016, 07:11
Нет никакой гарантии, что компилятор будет настолько умным, что распознает поддержку многопоточности и сделает сравнение объектов атомарным. Поэтому лучше мутекс.
Мда, в этом недостаток длинных тем - их никто не читает :) Если сравнение не атомарно - значит некорректно. Но это совсем не означает обратного - атомарность сравнения еще ничего не гарантирует.

Вообще у пользователей Qt как-то неважно с логикой :)


Название: Re: if (a == localA)
Отправлено: Old от Февраль 19, 2016, 08:10
Мда, в этом недостаток длинных тем - их никто не читает :)
Где вы видите длиную тему? Кое как наковыряли третью страницу.
В этом недостаток "непонятных" тем. Это да.

Если сравнение не атомарно - значит некорректно. Но это совсем не означает обратного - атомарность сравнения еще ничего не гарантирует.
О, капитан очевидность в теме. :)

Вообще у пользователей Qt как-то неважно с логикой :)
Точно. Эта темка в очередной раз это подтверждает, впрочем как и соседняя. :)