質問

GUIツールキットを使用したことがある場合は、すべてが完了した後に実行する必要があるイベントループ/メインループがあり、さまざまなイベントに対応してアプリケーションを実行し続けることができます。たとえば、Qtの場合、main()でこれを行います。

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

この場合、app.exec()はアプリケーションのメインループです。

この種のループを実装する明白な方法は次のとおりです。

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

しかし、これはCPUを100%に制限し、実用的ではありません。さて、CPUを完全に消費することなく応答するようなイベントループをどのように実装できますか?

回答はPythonおよび/またはC ++で高く評価されています。ありがとう。

脚注:学習のために、独自の信号/スロットを実装し、それらを使用してカスタムイベントを生成します(例:go_forward_event(steps))。ただし、システムイベントを手動で使用する方法を知っている場合は、それについてもお知らせします。

役に立ちましたか?

解決

以前は同じことをよく考えていました!

GUIのメインループは、擬似コードでは次のようになります。

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;
        }
    }
}

<!> quot; Waitable <!> quot;とは何ですか?まあ、それはシステムに依存しています。 UNIXでは、<!> quot; file descriptor <!> quot;と呼ばれます。および<!> quot; waitOnAll <!> quot; :: selectシステムコールです。いわゆるvector<Waitable>はUNIXでは::fd_setであり、<!> quot; whatHappened <!> quot; FD_ISSETを介して実際にクエリされます。実際の待機可能ハンドルはさまざまな方法で取得されます。たとえば、m_xConnectionは:: XConnectionNumber()から取得できます。 X11は、このための高レベルでポータブルなAPIも提供します-:: XNextEvent()-しかし、それを使用する場合、いくつかのイベントソースを同時に待機することはできません。

ブロッキングはどのように機能しますか? <!> quot; waitOnAll <!> quot; <!> quot; sleep list <!> quot;にプロセスを置くようにOSに指示するsyscallです。これは、いずれかのwaitableでイベントが発生するまでCPU時間を与えられないことを意味します。これは、プロセスがアイドル状態であり、CPUを0%消費していることを意味します。イベントが発生すると、プロセスは短時間反応してからアイドル状態に戻ります。 GUIアプリは、ほとんどの時間をアイドリングに費やします。

睡眠中のすべてのCPUサイクルはどうなりますか?依存します。別のプロセスがそれらを使用する場合があります。そうでない場合、OSはCPUをビジーループするか、一時的な低電力モードなどになります。

詳細についてはお問い合わせください!

他のヒント

Python:

ツイストリアクターの実装を見ることができます。これはおそらく、Pythonのイベントループの最適な実装です。 Twistedのリアクターはインターフェースの実装であり、実行するリアクターのタイプを指定できます:select、epoll、kqueue(すべてこれらのシステムコールを使用するac apiに基づく)、QTおよびGTKツールキットに基づくリアクターもあります。

単純な実装では、selectを使用します。

#echo server that accepts multiple client connections without forking threads

import select
import socket
import sys

host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input = [server,sys.stdin]
running = 1

#the eventloop running
while running:
    inputready,outputready,exceptready = select.select(input,[],[])

    for s in inputready:

        if s == server:
            # handle the server socket
            client, address = server.accept()
            input.append(client)

        elif s == sys.stdin:
            # handle standard input
            junk = sys.stdin.readline()
            running = 0

        else:
            # handle all other sockets
            data = s.recv(size)
            if data:
                s.send(data)
            else:
                s.close()
                input.remove(s)
server.close() 

一般的には、セマフォのカウントを使用してこれを行います。

>
  1. セマフォはゼロから始まります。
  2. セマフォでイベントループが待機します。
  3. イベントが入ると、セマフォがインクリメントされます。
  4. イベントハンドラは、セマフォのブロックを解除してデクリメントし、イベントを処理します。
  5. すべてのイベントが処理されると、セマフォはゼロになり、イベントループは再びブロックされます。

それほど複雑にしたくない場合は、ごく短いスリープ時間でwhileループにsleep()呼び出しを追加するだけで済みます。これにより、メッセージ処理スレッドはCPU時間を他のスレッドに譲ります。 CPUはもう100%に固定されませんが、それでもかなり無駄です。

scroll top