你将如何实现一个基本的事件循环? [英] How would you implement a basic event-loop?

查看:123
本文介绍了你将如何实现一个基本的事件循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果你使用gui工具包,你知道有一个事件循环/主循环,应该在一切完成后执行,这将保持应用程序的活动和响应不同的事件。例如,对于Qt,你可以在main()中执行:

If you have worked with gui toolkits, you know that there is a event-loop/main-loop that should be executed after everything is done, and that will keep the application alive and responsive to different events. For example, for Qt, you would do this in main():

int main() {
    QApplication app(argc, argv);
    // init code
    return app.exec();
}

在这种情况下,app.exec()是应用程序的主循环。

Which in this case, app.exec() is the application's main-loop.

实现这种循环的明显方法是:

The obvious way to implement this kind of loop would be:

void exec() {
    while (1) {
        process_events(); // create a thread for each new event (possibly?)
    }
}

但是这会使CPU达到100%,实用性无用。现在,我如何实现这样一个响应的事件循环,而不必一直使用CPU?

But this caps the CPU to 100% and is practicaly useless. Now, how can I implement such an event loop that is responsive without eating the CPU altogether?

答案在Python和/或C ++中是值得赞赏的。谢谢。

Answers are appreciated in Python and/or C++. Thanks.

脚注:为了学习,我将实现自己的信号/插槽,我将使用这些来生成自定义事件(例如 go_forward_event(steps))。但是如果你知道如何手动使用系统事件,我也想知道。

Footnote: For the sake of learning, I will implement my own signals/slots, and I would use those to generate custom events (e.g. go_forward_event(steps)). But if you know how I can use system events manually, I would like to know about that too.

推荐答案

很多都是一样的!

GUI主循环看起来像这样,在伪代码中:

A GUI main loop looks like this, in pseudo-code:

void App::exec() {
    for(;;) {
        vector<Waitable> waitables;
        waitables.push_back(m_networkSocket);
        waitables.push_back(m_xConnection);
        waitables.push_back(m_globalTimer);
        Waitable* whatHappened = System::waitOnAll(waitables);
        switch(whatHappened) {
            case &m_networkSocket: readAndDispatchNetworkEvent(); break;
            case &m_xConnection: readAndDispatchGuiEvent(); break;
            case &m_globalTimer: readAndDispatchTimerEvent(); break;
        }
    }
}

什么是 ?嗯,它是系统依赖。在UNIX上,它被称为文件描述符,waitOnAll是:: select系统调用。在UNIX上,所谓的向量< Waitable> 是一个 :: fd_set ,whatHappened FD_ISSET 。实际的等待句柄以各种方式获取,例如 m_xConnection 可以从:: XConnectionNumber()获取。 X11还为这个 - :: XNextEvent()提供了一个高级的,可移植的API - 但是如果你使用它,你将无法同时等待几个事件源

What is a "Waitable"? Well, it's system dependant. On UNIX it's called a "file descriptor" and "waitOnAll" is the ::select system call. The so-called vector<Waitable> is a ::fd_set on UNIX, and "whatHappened" is actually queried via FD_ISSET. The actual waitable-handles are acquired in various ways, for example m_xConnection can be taken from ::XConnectionNumber(). X11 also provides a high-level, portable API for this -- ::XNextEvent() -- but if you were to use that, you wouldn't be able to wait on several event sources simultaneously.

阻止如何工作? waitOnAll是一个系统调用,它告诉操作系统将你的进程放在睡眠列表上。这意味着,在其中一个waitables上发生事件之前,不会给出任何CPU时间。这意味着你的进程是空闲的,消耗0%的CPU。当事件发生时,您的进程将对其进行简短响应,然后返回空闲状态。

How does the blocking work? "waitOnAll" is a syscall that tells the OS to put your process on a "sleep list". This means you are not given any CPU time until an event occurs on one of the waitables. This, then, means your process is idle, consuming 0% CPU. When an event occurs, your process will briefly react to it and then return to idle state. GUI apps spend almost all their time idling.

在您睡觉时,所有CPU周期会发生什么?依靠。有时候,另一个进程将会对它们有用。

What happens to all the CPU cycles while you're sleeping? Depends. Sometimes another process will have a use for them. If not, your OS will busy-loop the CPU, or put it into temporary low-power mode, etc.

请询问更多详情!

这篇关于你将如何实现一个基本的事件循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆