Russian Qt Forum

Qt => Общие вопросы => Тема начата: fuCtor от Апрель 06, 2009, 16:42



Название: Connect и его разновидности
Отправлено: fuCtor от Апрель 06, 2009, 16:42
Люди добрые объясните пожалуйста в чем различие в процессе выполнения конектов:
  • QueuedConnection
  • BlockingQueuedConnection
Судя по документации:
Qt::QueuedConnection
Цитировать
When emitted, the signal is queued until the event loop is able to deliver it to the slot.
Qt::BlockingQueuedConnection
Цитировать
Same as QueuedConnection, except that the current thread blocks until the slot has been delivered. This connection type should only be used for receivers in a different thread. Note that misuse of this type can lead to dead locks in your application

Т.е. при выполнении конекта с блокированием потока из которого был произведен вызов. Но при выполнении всеравно сначала выполняется emit сигнала, invokeMethod и return, а только затем собственно связанный слот, т.е. поток не блокируется. Или я что-то не так понял?

Суть проблемы почему стало это критично, так это наверно извращенный случай, когда сигнал возвращает значение. При DirectConnection все нормально работает, пока вызывающих потоков не больше одного. Когда потоков уже два и более постоянно валится эксепшн. Попытка обвязать все вызовы мьютексами не помогла. Может есть какие решения?
Или как еще можно реализовать локальную комутацию нескольких потоков с объектом из главного, не перетаскивать же его каждый раз в выполняемый поток для этого, хотя чем не способ )


Название: Re: Connect и его разновидности
Отправлено: whirlwind от Апрель 06, 2009, 22:41
в Signals and Slots  (http://doc.trolltech.com/4.5/signalsandslots.html#signals) написано

Цитировать
Execution of the code following the emit statement will occur once all slots have returned. The situation is slightly different when using queued connections; in such a case, the code following the emit keyword will continue immediately, and the slots will be executed later.

т.е. разница как раз в том, что в одном случае поток, из которого пошел вызов будет заблокирован, а в другом -- нет.

Суть проблемы почему стало это критично, так это наверно извращенный случай, когда сигнал возвращает значение.
сигнал не может возвращать значение, об этом сказано там же, в Signals and slots. Это противоречит здравому смыслу: что возвратится, после того, как сработают подряд несколько слотов?


Название: Re: Connect и его разновидности
Отправлено: Sergeich от Апрель 06, 2009, 23:38
Qt::BlockingQueuedConnection работает приблизительно так: объект, эмитирующий сигнал пробегается по списку слотов или сигналов, соединенных с данным, для каждого ждущего этого сигнала объекта, в очередь событий нитки, который этот объект принадлежит, добавляется событие QEvent::MetaCall, после чего выполнение потока, в котором эмитируется сигнал, приостанавливается до тех пор, пока не завершится обработка всех событий QEvent::MetaCall, инициированных данным сигналом.
Если объект, вызвавший сигнал и его получатель принадлежат одной нитке - будет дедлок => надо проверять принадлежность объектов к разным ниткам перед вызовом connect c данным параметром.
Хотя эта фича довольно удобна в некоторых случаях, юзать ее надо с большой осторожностью. Если можно обойтись без нее - лучше не юзать.
Из собственного опыта: я юзал этот коннект, когда в дополнительной счетной нитке, в которой не было событийного цикла,  возникала какая-нибудь критическая ситуация - например, заканчивалось место на диске - и надо было предложить юзеру либо почистить диск, либо прервать выполнение.


Название: Re: Connect и его разновидности
Отправлено: fuCtor от Апрель 07, 2009, 05:46
сигнал не может возвращать значение, об этом сказано там же, в Signals and slots. Это противоречит здравому смыслу: что возвратится, после того, как сработают подряд несколько слотов?
Согласно здравому смыслу да, но технически это возможно, правда только при прямом соединении.

Qt::BlockingQueuedConnection работает приблизительно так: объект, эмитирующий сигнал пробегается по списку слотов или сигналов, соединенных с данным, для каждого ждущего этого сигнала объекта, в очередь событий нитки, который этот объект принадлежит, добавляется событие QEvent::MetaCall, после чего выполнение потока, в котором эмитируется сигнал, приостанавливается до тех пор, пока не завершится обработка всех событий QEvent::MetaCall, инициированных данным сигналом.
Если объект, вызвавший сигнал и его получатель принадлежат одной нитке - будет дедлок => надо проверять принадлежность объектов к разным ниткам перед вызовом connect c данным параметром.
Хотя эта фича довольно удобна в некоторых случаях, юзать ее надо с большой осторожностью. Если можно обойтись без нее - лучше не юзать.
Из собственного опыта: я юзал этот коннект, когда в дополнительной счетной нитке, в которой не было событийного цикла,  возникала какая-нибудь критическая ситуация - например, заканчивалось место на диске - и надо было предложить юзеру либо почистить диск, либо прервать выполнение.
В принципе так и думал, осталось ток разобраться на практике.
Только второй вопрос так  и остался открытым: как вызвать метод из основного потока, если при этом он должен вернуть еще значение?


Название: Re: Connect и его разновидности
Отправлено: Sergeich от Апрель 07, 2009, 12:41
Только второй вопрос так  и остался открытым: как вызвать метод из основного потока, если при этом он должен вернуть еще значение?
Никак. Не парься. Просто передавай в параметрах сигнала указатель на переменную и меняй значение переменной в слотах. Пример:
Код:
void WorkingThread::run()
{
  forever {
    bool ok = doSomethingUsefulOperation();
    if ( !ok ) {
      bool abort = false;
      emit abortRequested(&abort);
      if (abort)
        return;
    }
  }
}

void SomethingGuiClass::onAbortRequested( bool* abort )
{
   if ( QMessageBox::critical( this, tr("Error"), tr("Shit happened. Cancel job?") ) == QMessageBox::Ok )
     *abort = true;
   else
     *abort = false;
}