Название: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 00:31 Доброй ночи,
1. В общем дело таково: мне нужно приостановить выполнение потока, в принципе для этого есть условие ожидания QWaitCondition::wait(), но эта ф-ция принимает мютекс, мне же просто хочется приостановить поток, мютексом в холостую lock'aть unlock'ать как-то "по-быдлокодерски", есть какие-то варианты? 2. и еще одно: если у меня есть перечисление и переменная: Код: enum WorkState {run, stop, exit}; эту переменную workState разделяют 2 потока: workState = run; if (workState == stop) {} Вопрос: это атомарные операции? Спасибо Название: Re: Приостановить поток Отправлено: Igors от Ноябрь 20, 2011, 10:36 1) В любом случае требуется мутекс, семафор, на худой конец - атомарный лок
2) Эти операции атомарные, но чтение+запись такой переменной нужно защищать блокировками Название: Re: Приостановить поток Отправлено: alexman от Ноябрь 20, 2011, 11:49 1. void QThread::sleep ( unsigned long secs )
Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 11:50 1) В любом случае требуется мутекс, семафор, на худой конец - атомарный лок а что такое атомарный лок? и еще такой вопрос - с точки зрения произовдительности что лучше:lock() unlock() мютексом или release() aquire() семафором? в данном семафор всеравно будет использоваться как мютекс Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 11:51 1. void QThread::sleep ( unsigned long secs ) это не пойдет, неизвестно сколько потоку нужно спать, точнее будет его определенное событие (нажатие на кнопку)Название: Re: Приостановить поток Отправлено: alexman от Ноябрь 20, 2011, 12:35 Ну можно уснуть на немного и проверить состояние, если состояние не выполнено, то можно снова уснуть на немного, ... пока не получим необходимое состояние.
Название: Re: Приостановить поток Отправлено: BRE от Ноябрь 20, 2011, 12:56 1. В общем дело таково: мне нужно приостановить выполнение потока, в принципе для этого есть условие ожидания А у тебя не получится в холостую локать/унлокать. :)QWaitCondition::wait(), но эта ф-ция принимает мютекс, мне же просто хочется приостановить поток, мютексом в холостую lock'aть unlock'ать как-то "по-быдлокодерски", есть какие-то варианты? Тебе все равно потребуется какой-то "ресурс", что бы указать засыпать потоку или нет. Название: Re: Приостановить поток Отправлено: BRE от Ноябрь 20, 2011, 13:07 Ну можно уснуть на немного и проверить состояние, если состояние не выполнено, то можно снова уснуть на немного, ... пока не получим необходимое состояние. sleep "плохая" функция. :)IMHO, почти всегда (если не всегда) можно обойтись без нее и получить более эффективный код. Название: Re: Приостановить поток Отправлено: Igors от Ноябрь 20, 2011, 13:09 а что такое атомарный лок? и еще такой вопрос - с точки зрения произовдительности что лучше: Производительность мутекса и семафора одинакова (они сделаны на одних и тех же базовых примитивах ОС). Ну и скоростью оба не блещут. Поэтому если время останова достаточно мало (0.1 сек и меньше) то лучше атомарный лок, который не останавливает нитку (процессор работает) но позволяет продолжить выполнение когда условие достигнуто. Проще всего QAtomicInt::testAndSetAcquirelock() unlock() мютексом или release() aquire() семафором? в данном семафор всеравно будет использоваться как мютекс Ну можно уснуть на немного и проверить состояние, если состояние не выполнено, то можно снова уснуть на немного, ... пока не получим необходимое состояние. "Так защищаться можно", но 1) Возникают проблемы "а немного - это сколько ?" :) 2) Образуется неприятный "стык". Напр мы поставили условие true, а потом нужно опять false. Но неизвестно подхватила ли нитка наше true Название: Re: Приостановить поток Отправлено: alexman от Ноябрь 20, 2011, 16:04 Ну можно уснуть на немного и проверить состояние, если состояние не выполнено, то можно снова уснуть на немного, ... пока не получим необходимое состояние. sleep "плохая" функция. :)IMHO, почти всегда (если не всегда) можно обойтись без нее и получить более эффективный код. Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 16:08 все сделал с помощью мьютекса, один поток делает lock(), а второй после условия тоже пытается lock(),
но мьютекс закрыт, после возникновения события "продолжить" главный поток делает unlock(), думаю дальше идея ясна Название: Re: Приостановить поток Отправлено: alexman от Ноябрь 20, 2011, 16:08 1) Возникают проблемы "а немного - это сколько ?" :) 1. Эмпирически :)2) Образуется неприятный "стык". Напр мы поставили условие true, а потом нужно опять false. Но неизвестно подхватила ли нитка наше true 2. Это да. Ну как вариант можно конечно хранить массив значений состояния. В данной ситуации надо что-нибудь другое использовать. Название: Re: Приостановить поток Отправлено: Igors от Ноябрь 20, 2011, 16:25 все сделал с помощью мьютекса, один поток делает lock(), а второй после условия тоже пытается lock(), Так не пойдет. Правило: если нитка делает lock(), то она же (и только она) должна сделать unlock(). А если хотите делать из разных ниток - используйте семафорыно мьютекс закрыт, после возникновения события "продолжить" главный поток делает unlock(), думаю дальше идея ясна Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 18:09 Так не пойдет. Правило: если нитка делает lock(), то она же (и только она) должна сделать unlock(). А если хотите делать из разных ниток - используйте семафоры конечно переделать под семафоры не составит труда, но у меня возникает вопрос: это правилочисто "правило хорошего стиля" или у него есть какие-то предпосылки? Название: Re: Приостановить поток Отправлено: Igors от Ноябрь 20, 2011, 18:15 это правило чисто "правило хорошего стиля" или у него есть какие-то предпосылки? Это не имеет никакого отношения к стилю - нитка захватившая mutex (mutual exсlusion) должна его же и освободить, иначе результат не определенПо поводу "идея ясна" и "не составит труда" - "многопоточное программирование" только на первый взгляд кажется простым, но это не так :) Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 18:37 "многопоточное программирование" только на первый взгляд кажется простым, но это не так :) так с этим никто и не спорит :)Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 19:50 2) Эти операции атомарные, но чтение+запись такой переменной нужно защищать блокировками хотелось бы еще такое узнать, а если доступ к переменной через ссылку или через указатель:Код: 1. wState = &workState; 2 и 3 также будет атомарно? Название: Re: Приостановить поток Отправлено: Igors от Ноябрь 20, 2011, 23:10 2 и 3 также будет атомарно? Будет-то будет, но код в котором даже все операции атомарны может успешно рухнуть - потому что др нитка может вклиниться между операциями. Простой примерКод Здесь все атомарно, но тем не менее придется это место защищать блокировкой. Начиная от момента когда выполнилось a == b до момента когда выполнится a = 0 могло произойти многое, др нитка(и) могли изменить a и b как они хотели. Цитировать С Ларисой я действительно пил вино, но это было на пасху Название: Re: Приостановить поток Отправлено: qt_user от Ноябрь 20, 2011, 23:14 Будет-то будет, но код в котором даже все операции атомарны может успешно рухнуть - потому что др нитка может вклиниться между операциями. Простой пример Пасиба, это мы усвоили :)Код Здесь все атомарно, но тем не менее придется это место защищать блокировкой. Начиная от момента когда выполнилось a == b до момента когда выполнится a = 0 могло произойти многое, др нитка(и) могли изменить a и b как они хотели. Название: Re: Приостановить поток Отправлено: Igors от Ноябрь 20, 2011, 23:22 Пасиба, это мы усвоили :) Ну то так кажется - на эти грабли наступают все и много-много раз :)Название: Re: Приостановить поток Отправлено: JamS007 от Январь 03, 2012, 23:24 1. void QThread::sleep ( unsigned long secs ) лучше эту: void QThread::yieldCurrentThread () [static] она более "приближенная к системе", заставит передать управление другому потоку чтобы не тратить такты процессора в холостую. Название: Re: Приостановить поток Отправлено: qt_user от Январь 04, 2012, 00:33 1. void QThread::sleep ( unsigned long secs ) лучше эту: void QThread::yieldCurrentThread () [static] она более "приближенная к системе", заставит передать управление другому потоку чтобы не тратить такты процессора в холостую. отдает 1 свой квант другому потоку? В чем тогда разница QThread::yieldCurrentThread () и QThread::sleep("1 квант времени")? Название: Re: Приостановить поток Отправлено: JamS007 от Январь 04, 2012, 00:49 qt_user
yieldCurrentThread() передаст управление другой нити, и тем самым прекратит выполнение первой. Отличие от sleep() состоит в том, что в следующий раз поток будет "разбужен" когда этого захочет планировщик, а не по истечению интервала времени. из доки: void QThread::sleep ( unsigned long secs ) [static protected] Forces the current thread to sleep for secs seconds. 1. Нет никаких гарантий, что функция sleep() приведет к передаче управления другому потоку. Гипотетически - так должно быть, и наверное так часто и есть, но все-же. 2. Вы не сможете указать функции sleep() квант времени меньше 1 секунды, да есть msleep() но там Вы не сможете указать квант времени меньше 1 милисекунды. 3. sleep() только запускает механизм, который будет проверять прошел ли заданный промежуток времени или нет. Ничего не сказано о том, как эта проверка осуществляться. Она может выполниться 1 раз (через указанный промежуток времени) или 10 раз... Соответственно, за каждым разом будут потрачены ресурсы системы на сопоставление текущего времени с намеченным для пробуждения. В Вашем случае можно сэкономить эти затраты, ведь у вас уже есть условие, к которому можно привязаться (блокировка по мьютексу, а не точное время). Я даже встречал негативные отзывы в сторону boost::thread за функцию sleep(). Там она реализована таким образом, что сопоставляет время системы с запланированным для пробуждения, и если в ОС сменить время, к примеру, на день назад, то поток будет разбужен через день+интервал времени, заданный функции sleep(). Подозреваю, что в Qt также. Название: Re: Приостановить поток Отправлено: qt_user от Январь 04, 2012, 23:13 HaySayCheese
Спасибо большое, а то я много слышал что sleep плохо, но не видел да и не понимал как работает yieldCurrentThread() насчет пункта 2. есть еще QThread::usleep ( unsigned long usecs ) для микросекунд Название: Re: Приостановить поток Отправлено: BRE от Январь 04, 2012, 23:24 HaySayCheese Ну скорее sleep плохо не потому, что он не передает (или передает) управление другому потоку, а в неэффективности самого ожидания.Спасибо большое, а то я много слышал что sleep плохо, но не видел да и не понимал как работает yieldCurrentThread() Например, поток ожидает какие-то данные и пока их нет засыпает на одну секунду. Данные могут придти в любой момент, т.е. поток проверил и заснул, а в этот момент данные появились, поток все равно будет спать секунду, а только потом проснется и обнаружит данные для обработки, хотя могу бы уже секунду как работать. Поэтому, лучше использовать специальные механизмы, которые могут пробудить поток в тот момент, когда данные появились, например, условные переменные (QWaitCondition). Название: Re: Приостановить поток Отправлено: thechicho от Январь 06, 2012, 17:38 я чтобы сделать паузу в потоках, делал как-то так
.h потока public: bool условие; поток::run() { QEventLoop loopPause; if (условие) { connect(this, SIGNAL(pause()), &loopPause, SLOT(quit())); loopPause.exec(); } } слот потока::blabla() { emit pause(); } слот главного потока::клик_на_мышку_пауза() { if(поток->условие) { поток->условие = false; emit pause(); } else { поток->условие = true; } } слот главного потока::создаем_потоки() { for (int i = 0; i < 100500; i++) { класспотока *поток = new класспотока(this); поток->условие = false; connect(this, SIGNAL(pause()), поток, SLOT(blabla())); поток->погнали!; } } потом раскидывал if (условие) { connect(this, SIGNAL(pause()), &loopPause, SLOT(quit())); loopPause.exec(); перед затратными по времени операциями и усе. запускал по 500 потоков, работало все ч0тко.) Название: Re: Приостановить поток Отправлено: thechicho от Январь 06, 2012, 17:52 а не чуток по-другому, ща глянул.
при создании потоков connect(this, SIGNAL(pauseThreadTrueSignal()), thread, SLOT(pauseThreadTrueSlot())); connect(this, SIGNAL(pauseThreadFalseSignal()), thread, SLOT(pauseThreadFalseSlot())); connect(ui->pushButtonStart, SIGNAL(clicked()), this, SLOT(pauseSlot())); void гуи поток::pauseSlot() { if (isIconPlay) { emit pauseThreadTrueSignal(); } else { emit pauseThreadFalseSignal(); } } void поток::pauseThreadTrueSlot() { //qDebug() << "pauseThread: true"; pauseThread = true; if (workManual) emit labelStatusSignal("Пауза"); } void поток::pauseThreadFalseSlot() { //qDebug() << "pauseThread: false"; pauseThread = false; emit pauseDisabledSignal(); if (workManual) emit labelStatusClearSignal(); } if (pauseThread) { connect(this, SIGNAL(pauseDisabledSignal()), &loopPause, SLOT(quit())); loopPause.exec(); } isIconPlay - эт условие в гуи потоке (bool). я картинку делал прост, тип play, pause (еще и stop делал). короче работало все на ура. я хз, нафик заморачиваться с атомарными операциями, если так проще и работает без проблем. но дело ваше, конечно :) |