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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Ожидание на QEventLoop-е  (Прочитано 7490 раз)
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« : Ноябрь 25, 2020, 13:49 »

Возник вопрос, насколько безопасно так делать?

Код:
void wait() const
{
    QEventLoop waiter;

    QTimer timer;

    auto wait = [&]()
    {
        waiter.quit();
    };

    QObject::connect(&timer, &QTimer::timeout, this, wait);
    timer.start(1000);
    waiter.exec();
}
Ссылки в лямбде не протухнут на момент сработки таймера?
PS: вместо таймера можно подставить любой асинхронный объект, который триггернет лябду.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Ноябрь 30, 2020, 09:36 »

Возник вопрос, насколько безопасно так делать?
..
Ссылки в лямбде не протухнут на момент сработки таймера?
Не вижу тут никакой "опасности". Ссылки валидны т.к. упр-е остается в exec
PS: вместо таймера можно подставить любой асинхронный объект, который триггернет лябду.
А как он доберется до локального waiter?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #2 : Ноябрь 30, 2020, 10:19 »

А как он доберется до локального waiter?
А как сейчас таймер до него добирается?
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #3 : Ноябрь 30, 2020, 11:21 »

Ссылки валидны т.к. упр-е остается в exec
Вызов лямбды происходит в контексте другого потока (в общем случае), стек при вызове лямбды будет другой, как ссылка в новый стек "перетечет"?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Ноябрь 30, 2020, 11:52 »

Вызов лямбды происходит в контексте другого потока (в общем случае), стек при вызове лямбды будет другой, как ссылка в новый стек "перетечет"?
Никак не "перетечет", но не видно как позвать лямбду из др потока. Разве что сделать коннект с самоубийственным DirectConnection. А так (auto) прием будет в родном потоке, как и по таймеру

Др дело пользоваться этой конструкцией неудобно, коннект можно делать  "только здесь"
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #5 : Ноябрь 30, 2020, 13:19 »

Как позвать лямбду из другого потока. Например так:

Код:
class Async : public QObject
{
    Q_OBJECT

public:
    explicit Async(std::function<void()> callback, QObject* parent = nullptr)
        : QObject(parent)
        , m_callback(callback)
    {
    }

    void runAsync()
    {
        thread()->msleep(500);
        if (m_callback)
            m_callback();
    }

private:
    std::function<void()> m_callback;
};



class Waiter : public QObject
{
Q_OBJECT

public:
void wait() const
{
    QEventLoop waiter;

    auto wait = [&]()
    {
        waiter.quit();
    };

    Async async(wait);
    QtConcurrent::run(&async, &Async::runAsync);

    waiter.exec();
}

};
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Ноябрь 30, 2020, 13:43 »

Как позвать лямбду из другого потока. Например так:
Ну как-то это "не очень просто/естественно " Улыбающийся Если интересно "рухнет или нет" (из другого) - то да, рухнет, во всяком случае должно. Но написав waiter.exec Вы ясно показали что хотите делать все "легально". Ну и делайте, объявите waiter членом класса и добавьте слот c quit. Оформить ожидание "просто ф-цией" (возможно это цель?) - не стоит оно такого выноса мозга.
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #7 : Ноябрь 30, 2020, 13:59 »

Как позвать лямбду из другого потока. Например так:
Ну как-то это "не очень просто/естественно " Улыбающийся Если интересно "рухнет или нет" (из другого) - то да, рухнет, во всяком случае должно. Но написав waiter.exec Вы ясно показали что хотите делать все "легально". Ну и делайте, объявите waiter членом класса и добавьте слот c quit. Оформить ожидание "просто ф-цией" (возможно это цель?) - не стоит оно такого выноса мозга.
Последний приведенный пример у меня не падает.
Но подобные конструкции при больших нагрузках падали (а может и не они).
Что я хочу прояснить данной темой: что будет в лямбде при асинхронном ее вызове, и передаче туда ссылок на локальные переменные?
В стандарте что либо про это есть?
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #8 : Ноябрь 30, 2020, 14:41 »

Как позвать лямбду из другого потока. Например так:
Зачем тут лямбду городить, можно же проще:
Код
C++ (Qt)
class CWaitLoop : public QEventLoop
{
   Q_OBJECT
public:
   explicit CWaitLoop(QObject *parent = nullptr) : QEventLoop(parent) {}
   int wait(int msecs);
 
public slots:
   void exitSlot(int code) {
       QEventLoop::exit(code);
   }
};
 
int CWaitLoop::wait(int msecs){
   QTimer timer;
   timer.setSingleShot(true);
   timer.start(msecs);
   connect(&timer, &QTimer::timeout, this, &CWaitLoop::quit);
   return exec();
}
 
class AnyClass {
...
signals:
   void stopWaiting(int);
};
 
...
   AnyClass any;
   CWaitLoop waitLoop;
   connect(&any, &AnyClass::stopWaiting, &waitLoop, &CWaitLoop::exitSlot);
   int ret = waitLoop.wait(1000);
 
« Последнее редактирование: Ноябрь 30, 2020, 18:42 от sergek » Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #9 : Ноябрь 30, 2020, 17:15 »

Последний приведенный пример у меня не падает.
Он и не должен падать. quit потокобезопасен, вы его можете дергать из любого потока.

Что я хочу прояснить данной темой: что будет в лямбде при асинхронном ее вызове, и передаче туда ссылок на локальные переменные?
В стандарте что либо про это есть?
Лямбда захватит ссылку (читай указатель), пока эта ссылка будет валидна - никаких проблем не будет.
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #10 : Ноябрь 30, 2020, 17:28 »

Лямбда захватит ссылку (читай указатель), пока эта ссылка будет валидна - никаких проблем не будет.
Этот ответ меня устраивает, а примечание про указатель развеивает все сомнения.

Зачем тут лямбду городить, можно же проще:
Мне не надо как проще, мне нужно понять, как это работает.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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