glib を使用して を介してシグナルをディスパッチする場合emit
、すべての「リスナー」/ハンドラーが連続して呼び出されますか、または各リスナー/ハンドラーの後にイベント ループに制御が放棄されますか?
2 に答える
コールバックはすべて、メイン ループへの制御を放棄することなく連続して呼び出されます。
実際、私の知る限り、g_signal_emit() はすべてのハンドラーが呼び出されるまで制御を返さないため、メインループが起動する機会はありません。
したがって、この投稿のタイトルの質問に答えるには: いいえ、glib シグナルは非同期ではありません。
GLib シグナルは、同期または非同期で処理できます。GObject シグナルは常に同期します。つまり、シグナルを発行すると、シグナルが処理されるまで戻りません。GLib でシグナルを非同期に処理するには (簡潔にするために vala を使用しています - コードをプレーンな C に変換するために vala コンパイラを使用します)、シグナル Source を定義するか、IdleSource や TimeoutSource などの定義済みのものを使用する必要があります ( I/O は問題外です)。たとえば、関数があるとします
void my_func() {
stdout.puts("Hello world! (async)\n");
}
非同期で(同じスレッドから!)呼び出したい
void caller() {
// Here you want to insert the asynchronous call
// that will be invoked AFTER caller has returned.
// Body of caller follows:
stdout.puts("Hello world!\n");
}
方法は次のとおりです。
void caller() {
// Code for the asynchronous call:
var ev = new IdleSource();
ev.set_callback(() => {
my_func();
return Source.REMOVE; // Source.REMOVE = false
});
ev.attach(MainContext.default());
// Body of caller follows:
stdout.puts("Hello world!\n");
}
次の出力が得られます。
Hello world!
Hello world! (async)
my_func() 関数は、MainLoop がアイドル状態のときに実行されます (つまり、処理する他のシグナルがない)。特定の時間間隔が経過した後にトリガーするには、TimeoutSource 信号ソースを使用します。MainLoop が実行されている必要があります。そうでない場合、これは機能しません。
ドキュメンテーション: