Russian Qt Forum
Ноябрь 24, 2024, 12:54 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Вопрос о фальшивой синхронности  (Прочитано 7999 раз)
OKTA
Гость
« : Июнь 24, 2014, 21:11 »

Товарищи! Приветствую! Опишу вкратце ситуацию..
Есть программа, суть которой вернуть некий набор значений, есть у нее интерфейс и все работает хорошо.. Но тут понадобилось избавиться от интерфейса и превратить программу в библиотеку, используя в итоге только ее движок.
Но на все про все - выделили один метод, который просто возвращает результат работы всей программы (уже библиотеки  Строит глазки)..  Смеющийся Все бы ничего, но только в движке много всего и действия происходят асинхронно и просто так вернуть значения из метода не получится. Подскажите, как можно выкрутиться? Хотел использовать QEventLoop, из которого просто выходить как только будут готовы данные, но вычитал сегодня, что это крайне небезопасно и мало кем рекомендуется  В замешательстве
« Последнее редактирование: Июнь 26, 2014, 10:44 от OKTA » Записан
Bepec
Гость
« Ответ #1 : Июнь 24, 2014, 21:19 »

Эээ?  А где вычитали?

Я тоже хочу почитать, почему EventLoop, который используется в QThread, QApplication, QCoreApplication небезопасен???
Записан
OKTA
Гость
« Ответ #2 : Июнь 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/

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

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


Записан
Bepec
Гость
« Ответ #3 : Июнь 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 количество секунд. Именно эту проблему я тогда и решал таймером Веселый
3) Есть известная доля риска написать плохой код, но этот шанс есть всегда Улыбающийся
« Последнее редактирование: Июнь 24, 2014, 22:56 от Bepec » Записан
OKTA
Гость
« Ответ #4 : Июнь 24, 2014, 22:54 »

Да, вроде как-то так.. Но что мне-то делать?  Смеющийся
Чем череповато запускать QEventLoop, когда уже есть основной луп (внутри главного потока)? И как они будут дружить?
Записан
Bepec
Гость
« Ответ #5 : Июнь 24, 2014, 22:58 »

Запусти 10-15 потоков через QThread::run без moveToThread и увидишь, что ничего с 16 потоками не произошло Веселый
Собственно в чём мой скептицизм - этот ход используется в Qt Улыбающийся
Записан
OKTA
Гость
« Ответ #6 : Июнь 24, 2014, 23:03 »

Ну это будет 16 потоков с лупами внутри себя) А если внутри одного потока 16 QEventLoop-ов запустить?))
Проблема же основная в том, что пока ожидается возврат из асинхронного вызова с помощью QEventLoop, все другие события не прокакиваются  Плачущий
Ход с использованием QEventLoop для превращения асинхронности в синхронность или какой?)
« Последнее редактирование: Июнь 25, 2014, 00:14 от OKTA » Записан
Bepec
Гость
« Ответ #7 : Июнь 25, 2014, 06:26 »

Нееет. Это будет всё происходить в основном потоке. Луп работает на поток.
Мб вы не заметили, я специально указал что запускать потоки через run, а не через start Веселый

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

Сообщений: 4350



Просмотр профиля
« Ответ #8 : Июнь 25, 2014, 07:32 »

Ну это будет 16 потоков с лупами внутри себя) А если внутри одного потока 16 QEventLoop-ов запустить?))
Для каждой нитки создается своя очередь сообщений. Объект QEventLoop подключается к очереди той нитки, в которой он выполняется.
Не имеет значение, сколько создано объект QEventLoop (хоть 100500), все они работают с одной очередью и делают одинаковые вещи - обрабатываю события из этой очереди.

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

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Июнь 25, 2014, 08:29 »

Кстати, пользуясь случаем, скажите, прав ли я в следующем утверждении:
Если создаем QEvenLoop в объекте, то этот луп начинает обслуживать все события данного объекта, не касаясь лупа, который создается  в main? Если да, то верно ли то, что при переносе объекта в поток(с помозью moveToThread), отличный от основного, надо принудительно запускать exec для этого потока? Получается, что если этого не сделать, то все события продолжает обрабатывать QEventLoop от QApplication?
Пример: послано событие (или испущен сигнал с QueuedConnection). Находится нитка получателя (устанавливаемая moveToThread, никак не связана с текущей). Находится EventLoop данной нитки, текущий (активный, последний), и событие помещается в его очередь. Крутятся неск EventLoop в неск нитках - ну каждый парит свою очередь. Не вижу здесь ничего "опасного"
Записан
OKTA
Гость
« Ответ #10 : Июнь 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";
    }
};
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июнь 25, 2014, 11:30 »

Нельзя получать события таймера в теле его обработчика
Код
C++ (Qt)
void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
{
   WinTimerInfo *t = timerDict.value(timerId);
   if (t && !t->inTimerEvent) {

[/off]В след раз выложите пример чтобы можно было сразу компилить. А то пока copy/paste да хедеры приткнешь - весь интерес пропал  Улыбающийся
Записан
OKTA
Гость
« Ответ #12 : Июнь 25, 2014, 12:46 »

Ок, буду выкладывать целиком)

А кто здесь обработчик, а кто получатель? Чего-то я запутался в терминологии  В замешательстве
Записан
Bepec
Гость
« Ответ #13 : Июнь 25, 2014, 12:55 »

А нельзя ли попонятнее. А то я ничего не понимаю Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Июнь 25, 2014, 16:38 »

А кто здесь обработчик, а кто получатель? Чего-то я запутался в терминологии  В замешательстве
В слоте таймера Вы запустили QEventLoop. Обработка события таймера не закончена пока не выйдете из лупа. Поэтому слот не вызывается для этого таймера (для др пожалуйста) - страхуется от рекурса. В исходниках там все популярно изложено
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.073 секунд. Запросов: 23.