Название: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 25, 2013, 18:19 Здравствуйте!
Везде читал, что работа с моделью данных небезопасна в отношении потоков. Пришел момент столкнуться с этим, когда поток обрабатывает модель данных. Решил проверить, сделал тестовую программу. Сабж: создается глобальный потомок QAbstractListModel, который устанавливается в qml файл как свойство: Код: qmlRegisterType<ModuleDataModel>("CustomComponents", 1, 0, "ModuleDataModel"); Код: pModel->refreshModelData(8); После этого видим закономерный список с делегатами, соответствующими данным в модели. Теперь самое интересное: создаем класс, который в отдельном потоке будет обходить модель и считывать её значения: Код: TClass::TClass(ModuleDataModel *pModel, bool readOnly) : Код: ....main.... и.... всё работает! Программа выводит ожидаемое Цитировать started! 2 и неожиданное отсутствие ошибок.started! 0 started! 1 started! 3 Буду признателен советам, предложениям! Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Bepec от Май 25, 2013, 20:40 Незнаю где вы такого начитались, но модели потокобезопасны по моему разумению.
Ибо данные и прочее берутся по сигналам, сигналы ставятся в очередь, очередь разруливает обращение из разных потоков, разные потоки получают в свою очередь сигналы с данными и спокойно всё обрабатывают. PS покажите где вы это читали :D В контексте Qt пожалуйста. Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 25, 2013, 22:28 Ну наверное потому, что реализацию методов data и setData пишу я, так как это абстрактные функции.
что-то типа Код: QVariant ModuleDataModel::data(const int pos, int role) const Таким образом, работая с одной и той же моделью в двух и более потоках я просто обязан ломать модель не константной функцией setData, а именно в строке Код: m_moduleDataItems.replace(index1, moduleDataItem); p.s. мьютексы не использовал. Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Bepec от Май 25, 2013, 23:37 Вы не понимаете.Система сигнал слотов вызывает ваши эти функции последовательно из очереди событий потока.
Т.е. фактически вы пишите функцию, которая последовательно обрабатывает данные. Это система сигнал-слотов Qt. Почитайте о ней внимательнее... Смотрите: Сигнал-слотовая система потокобезопасна. Модель построена на сигнал-слотовой системе. Вывод - модель потокобезопасна. Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Авварон от Май 26, 2013, 00:39 Пиздец какой-то.
Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Авварон от Май 26, 2013, 09:59 Таки добрался к компу. Модели (да и вообще, все наследники QObject) НЕ потокобезопасны, они реентрантны. Это значит, что их можно использовать только из 1го потока в 1 момент времени.
Сигнал/слоты тут вообще нипричем, сигналом модель лишь уведомляет view об изменениях, а view уже дергает ф-ии модели напрямую. Вывод - модель и вью должны быть в одном потоке или все методы модели необходимо делать потокобезопасными. Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Странник от Май 26, 2013, 10:01 Вы не понимаете.Система сигнал слотов вызывает ваши эти функции последовательно из очереди событий потока. с какой бы радости сеттеры модели вызывались посредством сигнал-слотов? это обычные публичные методы, представление (или сам программист) должно дергать их напрямую. упоминаний о потокобезопасности классов моделей я тоже что-то не припомню. раньше в документации в описании класса вроде бы писали thread-safe, буде таковое имеется.Т.е. фактически вы пишите функцию, которая последовательно обрабатывает данные. Это система сигнал-слотов Qt. Почитайте о ней внимательнее... Смотрите: Сигнал-слотовая система потокобезопасна. Модель построена на сигнал-слотовой системе. Вывод - модель потокобезопасна. Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Igors от Май 26, 2013, 10:02 Таким образом, работая с одной и той же моделью в двух и более потоках я просто обязан ломать модель не константной функцией setData, а именно в строке Как читающий может догадаться кто такой ModuleDataItem? Возможно replace сводится к оператору = который в свою очередь разбивается на атомарные операции присвоения. Вообще трудно что-то сказать если Вы кормите только огрызками кода :)Код: m_moduleDataItems.replace(index1, moduleDataItem); Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 26, 2013, 13:38 //НЕ потокобезопасны, они реентрантны. Это значит, что их можно использовать только из 1го потока в 1 момент времени.
можете подробнее объяснить? разве что-то вообще можно использовать в разных потоках в 1 момент времени? в плане безопасности. нужно же лочить все равно... или, если потокобезопасны, то обращение к таким переменным автоматически лочиться чтоле? а реентрантные нужно вручную лочить, при одновременном доступе к ним из разных потоков? под лочить имею в виду Код: mutex.lock(); Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 26, 2013, 17:48 Предпочитаю QMutexLocker, так как не знаешь где сделаешь выход из функции.
Верес, функция модели setData вызывается напрямую, по этому да. Таки "реентрантны". Igors, совершенно верно во всех отношениях. К сожалению маленький опыт приводит к таким вот оплошностям. Итог: работа с присвоением в функции setData идет на атомарном уровне, по этому не происходит сбоя. Всем большое спасибо. Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Igors от Май 26, 2013, 18:00 Итог: работа с присвоением в функции setData идет на атомарном уровне, Ну может и не на атомарном, напрКод Присваивание double может быть не атомарно, но это не ведет ни к какому краху - просто получается неверный результат (что намного хуже для отлова) Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 26, 2013, 18:35 //Предпочитаю QMutexLocker, так как не знаешь где сделаешь выход из функции
как это не знаешь? у вас функция на миллион строк? а что именно лочить то, надеюсь, знаете? или не знаете, поэтому и предпочитаете?) Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: Авварон от Май 26, 2013, 21:29 //НЕ потокобезопасны, они реентрантны. Это значит, что их можно использовать только из 1го потока в 1 момент времени. Из разных потоков можно использовать потокобезопасные методы/классы. Пример - функция QObject::connect() потокобезопасна, ее можно звать из любого потока без всяких блокировок объектов.можете подробнее объяснить? разве что-то вообще можно использовать в разных потоках в 1 момент времени? в плане безопасности. нужно же лочить все равно... или, если потокобезопасны, то обращение к таким переменным автоматически лочиться чтоле? а реентрантные нужно вручную лочить, при одновременном доступе к ним из разных потоков? под лочить имею в виду Код: mutex.lock(); А вот методы QString'а дергать из разных потоков не стоит. Но если заблокировать доступ к объекту, то можно дергать поочереди (сначала один поток поменял, потом второй). Это реентрантный класс. А вот всякие QWidget'ы вообще нельзя трогать из негуевого потока - это нереентрантный класс, даже навесив блокировки. Код: как это не знаешь? у вас функция на миллион строк? а что именно лочить то, надеюсь, знаете? или не знаете, поэтому и предпочитаете?) Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 26, 2013, 23:32 Igors, спасибо, запомню. Хотя если речь о том, что 4-х байтный double может слететь на 16-битной оси - это нормально.
Вопрос стоял в том, почему программа не вылетает, оказалось что в атомарности процесса присваивания используемой структуры. thechicho, Рефакторить легче, выглядит опрятнее. Я вообще стараюсь все объекты, которые входят куда-то и выходят реализовывать через такие вот обертки. Авварон Да, я использовал QMetaObject::invokeMetod с аргументом Qt::QueuedConnection когда это было возможно и обоснованно (к примеру setText в QLabel). Но иногда это не выгодно. Например когда есть важность в последовательности действий. Например когда в функции ты считываешь параметры прибора, а потом исходя из этих параметров снимаешь данные, и эти же параметры где-то выгребаются по таймеру. Конечно, есть ещё Qt::BlockingQueuedConnection, но пока это круто для меня. Пришлось делать тестовое ПО с несколькими потоками и одной моделью, привязанной к гую. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 27, 2013, 11:17 //Пример - функция QObject::connect() потокобезопасна, ее можно звать из любого потока без всяких блокировок объектов.
сорри, можете пояснить этот пример? я думал защищать от одновременно доступа нужно переменные. как может быть одновременный доступ к методу? и в данном случае QObject::connect() к чему одновременный доступ будет? ведь объекты же разные и переменные у них разные будут? или как? //А вот методы QString'а дергать из разных потоков не стоит. Но если заблокировать доступ к объекту, то можно дергать поочереди (сначала один поток поменял, потом второй). можете пример показать, где это нужно? просто не вижу смысла вызывать у одной переменной QString методы из разных потоков. хотя у меня опыт небольшой, мне приходилось лочить только список, когда разные потоки могли одновременно к нему обращаться и считывать элемент списка. ну еще и булевы переменные лочил. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: Igors от Май 27, 2013, 11:24 Хотя если речь о том, что 4-х байтный double может слететь на 16-битной оси - это нормально. 8-байтный double (или long long) может успешно слететь на 64-битной оси :) Но суть не в том "атомарно или нет", ошибка (отсутствие нужной блокировки) в большинстве случаев не ведет к вылету (это еще хорошо), а просто тихо гадит, напрВопрос стоял в том, почему программа не вылетает, оказалось что в атомарности процесса присваивания используемой структуры. Код
Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 27, 2013, 13:42 Ой, да. 8-ми байтный :)))
Спасибо, не знал что гадит. А что такое нитками? thechicho атомарные переменные и члены структур лочить не надо. Можете написать тестовую программку и посмотреть. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 27, 2013, 14:29 //атомарные переменные и члены структур лочить не надо
чо? Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 27, 2013, 16:06 Если процессор за один такт заменит значение, то считай оно уже залочено. Луркай "volatile" и "атомарный". Членов классов и структур это тоже касается.
Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 27, 2013, 16:19 //Если процессор за один такт заменит значение, то считай оно уже залочено.
Код: connect(this, SIGNAL(stopThread()), thread, SLOT(stopThread())); из главного потока посылается сигнал на остановку потоков. то есть не надо лочить STOP? значение переменной хранится в памяти и мьютекс нужен, чтобы избежать одновременного доступа к одному участку памяти. причем тут процессор? Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 27, 2013, 17:19 STOP = true выполняется за один такт процессора, и если ты создаешь пару потоков с одной и той же функцией
Код: void func() вылета не будет. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 27, 2013, 17:23 а кто говорил, про вылет?
Цитировать Но суть не в том "атомарно или нет", ошибка (отсутствие нужной блокировки) в большинстве случаев не ведет к вылету (это еще хорошо), а просто тихо гадит, напр ты походу сам не понимаешь о чем говоришь Название: Re: Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 27, 2013, 23:22 Пиздец какой-то. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: Serr500 от Май 28, 2013, 08:12 STOP = true выполняется за один такт процессора Шо, всегда? ;) ;DНазвание: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: Igors от Май 28, 2013, 10:24 По поводу "тактов" - присваивание может обращаться к памяти, и тогда неизвестно сколько тактов понадобится процессору. Другое довольно популярное заблуждение что, якобы, "атомарно все что делается одной машинной командой". Напр в одной статье видел примерно такое
Код: inc [offset] "Если атомарно - можно обойтись без лока" - это часто оказывается ошибкой, напр Код Все атомарно, но др нитка може вклиниться между 2-мя атомарными командами. Испуганный человек начинает страховаться и сует мутексы на каждом шагу. В результате 4 ядоа оказываются куда медленнее одного :) Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 28, 2013, 11:34 я сделаю приложение, где четыре потока без задержек будут ставить в одну переменную double либо 0, либо 10, и если перед этим будет не 0 или не 10 - выводить наружу значение через qDebug.
Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 28, 2013, 12:09 //Испуганный человек начинает страховаться и сует мутексы на каждом шагу. В результате 4 ядоа оказываются куда медленнее одного
ога медленнее на пару микросекунд :) в моем случае у меня 100500 проверок STOP. так что можно и без мьютекса написать, ничего от этого не изменится. но какбэ теория намекает, что нужно защищать переменную от одновременного доступа блокировкой. эта блокировка сработает единожды и произойдет выход из потоков и их уничтожение. то есть остановка. о какой скорости может идти речь. да и вообще в контексте мьютекса можете пример привести, где он может повлиять значительно на скорость выполнения? требуются же микросекунды на лок, анлок Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 28, 2013, 12:13 //я сделаю приложение, где четыре потока без задержек будут ставить в одну переменную double либо 0, либо 10, и если перед этим будет не 0 или не 10 - выводить наружу значение через qDebug.
и какой в этом смысл? http://www.youtube.com/watch?v=JaGqGhRW5Ks Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: Igors от Май 28, 2013, 13:06 я сделаю приложение, где четыре потока без задержек будут ставить в одну переменную double либо 0, либо 10, и если перед этим будет не 0 или не 10 - выводить наружу значение через qDebug. Цитировать Тестирование может показать наличие ошибок но не их отсутствие :) Попробуйте такКод А можно действовать проще - пройдите в отладчике по шагам Код Правда, насколько я знаю, эта радость доступна начиная с С++ 11. Внутри присваивания Вы увидите что все далеко не так просто Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 28, 2013, 21:31 Есть случаи тривиальные, типа
if(a > b) b = a; Мы говорили о присваивании и ошибках. Вот код Код: while(qApp && m_running) Справедливости ради замечу, что код Код: if(m_pModel->m_value != 0 && m_pModel->m_value != 11) Цитировать Ii-ia! 0 Ii-ia! 0 Ii-ia! 0 Ii-ia! 0 Ii-ia! 0 Ii-ia! 11 где m_value имеет тип double Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 28, 2013, 21:34 thechicho,
Вы не писали крупных проектов, где в потоках происходят реально медленные функции? Из за них и замедляется lock -> unlock, а не из за скорости самого mutex. Короче, да. Ошибка в большинстве случаев тихо гадит, но если писать с умом то этого можно избежать. Правда, тогда это будет говнокод :) Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 29, 2013, 09:18 //Вы не писали крупных проектов, где в потоках происходят реально медленные функции? Из за них и замедляется lock -> unlock, а не из за скорости самого mutex.
:-\ каким образом замедляется? примеры адекватные привидите. цифры насколько замедляется привидите. и обоснуйте почему такое "замедление" неприемлимо. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 29, 2013, 13:24 Я встречал два проявления: функции, использующие блокировку долгих процессов выстраиваются в очередь, как в машины в пробке, из за чего последняя выполняется дико долго и второе: потоковое голодание, когда функции вызываются часто и какой-то поток просто не входит в функцию вообще.
Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: Igors от Май 29, 2013, 13:30 который проработал час в трех потоках, загрузив на 75% мой проц Такие тесты долгие и могут ничего не показать. Я Вам прозрачно намекал: проблемы возможны когда адрес double не кратен 8 (во всяком случае так в atomic реализвции Intel)Товарищ mutex совсем не из Парижской Коммуны и может замедлить выполнение значительно, иногда катастрофично. Есть "честные" мутексы и нет (у меня только бесчестные :)). В общем это длинный и не очень конкретный разговор, поэтому умолкаю Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 29, 2013, 15:32 //функции, использующие блокировку долгих процессов выстраиваются в очередь, как в машины в пробке, из за чего последняя выполняется дико долго
может это не проблема мьютексов, а проблема того, кто таким образом решил задачу? водители же не виноваты, что архитектор не все предусмотрел. //потоковое голодание, когда функции вызываются часто и какой-то поток просто не входит в функцию вообще. как это возможно? у меня поток - объект-наследник QThread. у каждого объекта своя память. каждый поток делает свою работу. покажите конкретный адекватный пример такого случая? Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 29, 2013, 15:37 //может замедлить выполнение значительно, иногда катастрофично
старые песни о главном :) опять никакой конкретики. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: mutineer от Май 29, 2013, 15:46 у меня поток - объект-наследник QThread. у каждого объекта своя память. Можешь пояснить в каком смысле у каждого объекта своя память? Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 29, 2013, 15:51 в том смысле, что у каждого потока своя функция (свой адрес в памяти). это было сказано в контексте
//когда функции вызываются часто и какой-то поток просто не входит в функцию вообще возможно я что-то не понимаю, но я не вижу как такое возможно в моей реализации Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: mutineer от Май 29, 2013, 15:57 в том смысле, что у каждого потока своя функция (свой адрес в памяти) Если потоки это инстансы одного и того же класса, то функция (какая-то конкретная) как объект в памяти у них одна на всех... Либо я опять не понял о чем речь Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: ctin от Май 29, 2013, 16:17 Igors,
Аааа! Намек понял-с! Igors, Голодание - редкий случай. Там надо смотреть о приоритетах потоков и с мьютексами это почти не связано. Дело в том, что частый вызов ОС распределяет между потоками, и там нет строгой очереди. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: thechicho от Май 29, 2013, 16:53 //Если потоки это инстансы одного и того же класса, то функция (какая-то конкретная) как объект в памяти у них одна на всех...
хз, я думал под каждый объект класса выделяется своя область памяти. соответственно у полей и методов объекта, свои адреса. ctin, встречал - редкий случай, связано - почти не связано. походу с Igors взяли пример лить воду (писать умные, вроде бы, умозаключения) без конкретных примеров. Название: Re: [РЕШЕНО] Потоки и модель данных, или немного эзотерики. Отправлено: mutineer от Май 29, 2013, 16:55 //Если потоки это инстансы одного и того же класса, то функция (какая-то конкретная) как объект в памяти у них одна на всех... хз, я думал под каждый объект класса выделяется своя область памяти. соответственно у полей и методов объекта, свои адреса. Память выделяется для каждого объекта своя, но для полей. Методы копировать нет никакого смысла, они хранятся одни раз, независимо от количества объектов |