简体   繁体   中英

How can I queue a function to be executed in a Qt application's main thread with as high priority as possible?

I would like to be able to have a separate thread queue a std::function to be executed in a Qt application's main thread with as high a priority as possible, meaning that executing this function takes precedence over anything else that is happening in the main thread, save for any task the main thread is currently executing. (To clarify, the currently executing task in the main thread doesn't need to yield execution or anything like that. This queued function should simply be the very next event that the thread processes with as little delay as possible.)

There are a number of ways a thread can set up a function to be called in another specific QThread , such as using a single shot QTimer with a zero second interval, or using QMetaObject::invokeMethod . But I'm not sure how execution of the function will be prioritized in relation to other tasks that are being processed by the main thread.

The first thought I had was to create a custom QEvent that contains an instance of the function I want to execute, write a handler for the new custom event type that executes the function, and then post it using something like:

qApp->postEvent(qApp, customEvent, Qt::HighEventPriority * 1000000);

...or using some other suitable huge integer for the event priority. I'm not sure if this is the best way to go about doing this since I don't have deep knowledge of how Qt's event system works. (Like how would this be prioritized in relation to events dispatched to other QObject 's whose thread affinity is set to the main thread?)

Is there a better method?

Here is the solution I settled on:

#define kFunctionEventType ((QEvent::Type)(QEvent::User + 1))

class FunctionEvent : public QEvent {
public:
    FunctionEvent(const std::function<void()> &inFunc) : QEvent(kFunctionEventType), func(inFunc){};
    std::function<void()> func;
};

class FunctionEventReceiver : public QObject {
    Q_OBJECT
public:
    explicit FunctionEventReceiver() : QObject(nullptr) {};
    virtual bool event(QEvent *event);
};

static FunctionEventReceiver * functionEventReceiver()
{
    static FunctionEventReceiver receiver;
    return &receiver;
}

bool FunctionEventReceiver::event(QEvent *event)
{
    if (event->type() != kFunctionEventType) {
        return QObject::event(event);
    }
    
    FunctionEvent *functionEvent = (FunctionEvent *)event;
    functionEvent->func();
    functionEvent->accept();
    
    return true;
}

void executeInMainThreadWithMaximumPriority(const std::function<void ()> &func)
{
    FunctionEvent *event = new FunctionEvent(func);
    qApp->postEvent(functionEventReceiver(), event, INT_MAX);
}

void initialize()
{
    // Ensures receiver is created in main thread:
    functionEventReceiver();
}

The one caveat is that I must call initialize() at the start of my app to ensure that the event receiver is created and associated with the application's main thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM