Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: RedDog от Ноябрь 25, 2020, 13:49



Название: Ожидание на QEventLoop-е
Отправлено: RedDog от Ноябрь 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: вместо таймера можно подставить любой асинхронный объект, который триггернет лябду.


Название: Re: Ожидание на QEventLoop-е
Отправлено: Igors от Ноябрь 30, 2020, 09:36
Возник вопрос, насколько безопасно так делать?
..
Ссылки в лямбде не протухнут на момент сработки таймера?
Не вижу тут никакой "опасности". Ссылки валидны т.к. упр-е остается в exec
PS: вместо таймера можно подставить любой асинхронный объект, который триггернет лябду.
А как он доберется до локального waiter?


Название: Re: Ожидание на QEventLoop-е
Отправлено: Old от Ноябрь 30, 2020, 10:19
А как он доберется до локального waiter?
А как сейчас таймер до него добирается?


Название: Re: Ожидание на QEventLoop-е
Отправлено: RedDog от Ноябрь 30, 2020, 11:21
Ссылки валидны т.к. упр-е остается в exec
Вызов лямбды происходит в контексте другого потока (в общем случае), стек при вызове лямбды будет другой, как ссылка в новый стек "перетечет"?


Название: Re: Ожидание на QEventLoop-е
Отправлено: Igors от Ноябрь 30, 2020, 11:52
Вызов лямбды происходит в контексте другого потока (в общем случае), стек при вызове лямбды будет другой, как ссылка в новый стек "перетечет"?
Никак не "перетечет", но не видно как позвать лямбду из др потока. Разве что сделать коннект с самоубийственным DirectConnection. А так (auto) прием будет в родном потоке, как и по таймеру

Др дело пользоваться этой конструкцией неудобно, коннект можно делать  "только здесь"


Название: Re: Ожидание на QEventLoop-е
Отправлено: RedDog от Ноябрь 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();
}

};


Название: Re: Ожидание на QEventLoop-е
Отправлено: Igors от Ноябрь 30, 2020, 13:43
Как позвать лямбду из другого потока. Например так:
Ну как-то это "не очень просто/естественно " :) Если интересно "рухнет или нет" (из другого) - то да, рухнет, во всяком случае должно. Но написав waiter.exec Вы ясно показали что хотите делать все "легально". Ну и делайте, объявите waiter членом класса и добавьте слот c quit. Оформить ожидание "просто ф-цией" (возможно это цель?) - не стоит оно такого выноса мозга.


Название: Re: Ожидание на QEventLoop-е
Отправлено: RedDog от Ноябрь 30, 2020, 13:59
Как позвать лямбду из другого потока. Например так:
Ну как-то это "не очень просто/естественно " :) Если интересно "рухнет или нет" (из другого) - то да, рухнет, во всяком случае должно. Но написав waiter.exec Вы ясно показали что хотите делать все "легально". Ну и делайте, объявите waiter членом класса и добавьте слот c quit. Оформить ожидание "просто ф-цией" (возможно это цель?) - не стоит оно такого выноса мозга.
Последний приведенный пример у меня не падает.
Но подобные конструкции при больших нагрузках падали (а может и не они).
Что я хочу прояснить данной темой: что будет в лямбде при асинхронном ее вызове, и передаче туда ссылок на локальные переменные?
В стандарте что либо про это есть?


Название: Re: Ожидание на QEventLoop-е
Отправлено: sergek от Ноябрь 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);
 


Название: Re: Ожидание на QEventLoop-е
Отправлено: Old от Ноябрь 30, 2020, 17:15
Последний приведенный пример у меня не падает.
Он и не должен падать. quit потокобезопасен, вы его можете дергать из любого потока.

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


Название: Re: Ожидание на QEventLoop-е
Отправлено: RedDog от Ноябрь 30, 2020, 17:28
Лямбда захватит ссылку (читай указатель), пока эта ссылка будет валидна - никаких проблем не будет.
Этот ответ меня устраивает, а примечание про указатель развеивает все сомнения.

Зачем тут лямбду городить, можно же проще:
Мне не надо как проще, мне нужно понять, как это работает.