Russian Qt Forum

Qt => Общие вопросы => Тема начата: OKTA от Июнь 24, 2014, 21:11



Название: [РЕШЕНО] Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 24, 2014, 21:11
Товарищи! Приветствую! Опишу вкратце ситуацию..
Есть программа, суть которой вернуть некий набор значений, есть у нее интерфейс и все работает хорошо.. Но тут понадобилось избавиться от интерфейса и превратить программу в библиотеку, используя в итоге только ее движок.
Но на все про все - выделили один метод, который просто возвращает результат работы всей программы (уже библиотеки  ::))..  ;D Все бы ничего, но только в движке много всего и действия происходят асинхронно и просто так вернуть значения из метода не получится. Подскажите, как можно выкрутиться? Хотел использовать QEventLoop, из которого просто выходить как только будут готовы данные, но вычитал сегодня, что это крайне небезопасно и мало кем рекомендуется  :-\


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Bepec от Июнь 24, 2014, 21:19
Эээ?  А где вычитали?

Я тоже хочу почитать, почему EventLoop, который используется в QThread, QApplication, QCoreApplication небезопасен???


Название: Re: Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 24, 2014, 21:51
http://developer.nokia.com/community/wiki/How_to_wait_synchronously_for_a_Signal_in_Qt
http://delta.affinix.com/2006/10/23/nested-eventloops/

Вот эти страшные статейки  ;D Небезопасно не вообще, а в конкретных ситуациях)
Я никогда не трогал QEventLoop и теперь боюсь начать не с той ноги  ;D

Кстати, пользуясь случаем, скажите, прав ли я в следующем утверждении:
Если создаем QEvenLoop в объекте, то этот луп начинает обслуживать все события данного объекта, не касаясь лупа, который создается  в main? Если да, то верно ли то, что при переносе объекта в поток(с помозью moveToThread), отличный от основного, надо принудительно запускать exec для этого потока? Получается, что если этого не сделать, то все события продолжает обрабатывать QEventLoop от QApplication?




Название: Re: Вопрос о фальшивой синхронности
Отправлено: Bepec от Июнь 24, 2014, 22:40
Ну попробую ответить, заодно и самому себе.

Моё представление:
1) EventLoop работает на поток, а не объект. Таким образом при запуске в main он перекроет основной :)
2) Соответственно исходя из первого ответа зависит от потока.

Если в QThread в ф-ции Run:
1) не запускать QEventLoop::exec, то в данном потоке тупо не будет сигнал-слотов. Следует понимать, что прямые соединения работать будут за счёт прямых же вызовов.
2) если вызвать QEventLoop::exec (что равнозначно QThread::run), то заработает полноценный механизм сигнал слотов.

Как то так.

update:
Почитал статейки.
1) Мб это покажет и мою неопытность, но проблема высосана из пальца во 2  статейке. Точно так же пишут статьи про goto. Это опасно, не используйте это, а если рекурсивно 2 goto поставить, то они ... неожиданно вызовут рекурсию :)
2) В 1 ссылке чётко сказано - не рекомендуется из-за возможных рекурсий. Но ошибка в том коде, что сигнала по разным причинам может не быть, потому приложение вечно крутит цикл. Собственно эту проблему мы и решаем в коде, ставя таймер на N количество секунд. Именно эту проблему я тогда и решал таймером :D
3) Есть известная доля риска написать плохой код, но этот шанс есть всегда :)


Название: Re: Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 24, 2014, 22:54
Да, вроде как-то так.. Но что мне-то делать?  ;D
Чем череповато запускать QEventLoop, когда уже есть основной луп (внутри главного потока)? И как они будут дружить?


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Bepec от Июнь 24, 2014, 22:58
Запусти 10-15 потоков через QThread::run без moveToThread и увидишь, что ничего с 16 потоками не произошло :D
Собственно в чём мой скептицизм - этот ход используется в Qt :)


Название: Re: Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 24, 2014, 23:03
Ну это будет 16 потоков с лупами внутри себя) А если внутри одного потока 16 QEventLoop-ов запустить?))
Проблема же основная в том, что пока ожидается возврат из асинхронного вызова с помощью QEventLoop, все другие события не прокакиваются  :'(
Ход с использованием QEventLoop для превращения асинхронности в синхронность или какой?)


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Bepec от Июнь 25, 2014, 06:26
Нееет. Это будет всё происходить в основном потоке. Луп работает на поток.
Мб вы не заметили, я специально указал что запускать потоки через run, а не через start :D

enum QEventLoop::ProcessEventsFlag - позволяет убирать зависания, пропуская нотификаторы или пользовательские действия.


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Old от Июнь 25, 2014, 07:32
Ну это будет 16 потоков с лупами внутри себя) А если внутри одного потока 16 QEventLoop-ов запустить?))
Для каждой нитки создается своя очередь сообщений. Объект QEventLoop подключается к очереди той нитки, в которой он выполняется.
Не имеет значение, сколько создано объект QEventLoop (хоть 100500), все они работают с одной очередью и делают одинаковые вещи - обрабатываю события из этой очереди.

Проблема же основная в том, что пока ожидается возврат из асинхронного вызова с помощью QEventLoop, все другие события не прокакиваются  :'(
Как раз все там "прокакивается". :)
Обрабатываются все события из своей очереди (если вы сами ничего не запрещали), точно так же, как это бы делалось в QCoreApplication::exec, QThread::exec. Код выполняется один и тот же.


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Igors от Июнь 25, 2014, 08:29
Кстати, пользуясь случаем, скажите, прав ли я в следующем утверждении:
Если создаем QEvenLoop в объекте, то этот луп начинает обслуживать все события данного объекта, не касаясь лупа, который создается  в main? Если да, то верно ли то, что при переносе объекта в поток(с помозью moveToThread), отличный от основного, надо принудительно запускать exec для этого потока? Получается, что если этого не сделать, то все события продолжает обрабатывать QEventLoop от QApplication?
Пример: послано событие (или испущен сигнал с QueuedConnection). Находится нитка получателя (устанавливаемая moveToThread, никак не связана с текущей). Находится EventLoop данной нитки, текущий (активный, последний), и событие помещается в его очередь. Крутятся неск EventLoop в неск нитках - ну каждый парит свою очередь. Не вижу здесь ничего "опасного"


Название: Re: Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 25, 2014, 09:44
Ну вот простой пример, когда в одном потоке два лупа создается и при этом события таймера из main прекращают поступать. Это я и имел ввиду под не прокакиваются.
main:
Код:
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    classA a1;
    QTimer timer;
    QObject::connect(&timer, SIGNAL(timeout()), &a1, SLOT(foo()));
    timer.start(200);

    return a.exec();
}
classA:
Код:
class classA : public QObject
{
    Q_OBJECT
    int counter1, counter2;
    QTimer timer;
   
public:
    classA() : counter1(0), counter2(0){}
    ~classA(){}

public slots:
    void foo() {
        //
       
        ++counter1;
        qDebug() << counter1 << "FOO";
       
        if(counter1 == 10) {
            timer.start(200);
            connect(&timer, SIGNAL(timeout()), this, SLOT(foo2()));
            QEventLoop lp;
            lp.exec();
        }
    }
    void foo2() {
        //
       
        ++counter2;
        qDebug() << counter2 << "FOO2";
    }
};


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Igors от Июнь 25, 2014, 11:30
Нельзя получать события таймера в теле его обработчика
Код
C++ (Qt)
void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
{
   WinTimerInfo *t = timerDict.value(timerId);
   if (t && !t->inTimerEvent) {

[/off]В след раз выложите пример чтобы можно было сразу компилить. А то пока copy/paste да хедеры приткнешь - весь интерес пропал  :)


Название: Re: Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 25, 2014, 12:46
Ок, буду выкладывать целиком)

А кто здесь обработчик, а кто получатель? Чего-то я запутался в терминологии  :-\


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Bepec от Июнь 25, 2014, 12:55
А нельзя ли попонятнее. А то я ничего не понимаю :)


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Igors от Июнь 25, 2014, 16:38
А кто здесь обработчик, а кто получатель? Чего-то я запутался в терминологии  :-\
В слоте таймера Вы запустили QEventLoop. Обработка события таймера не закончена пока не выйдете из лупа. Поэтому слот не вызывается для этого таймера (для др пожалуйста) - страхуется от рекурса. В исходниках там все популярно изложено


Название: Re: Вопрос о фальшивой синхронности
Отправлено: Bepec от Июнь 25, 2014, 18:19
Уху, дошло. И правильно ведь. Вот и защита от бяк всяких с евент лупами встроенная :D


Название: Re: Вопрос о фальшивой синхронности
Отправлено: OKTA от Июнь 25, 2014, 20:01
Да, спасибо  :)