単純なプログラミング言語のCでバイトコードインタープリターを書いています。
言語にGUI機能を追加したい。最初のステップとして、GTKライブラリのラッパーをインタープリターに焼き込むことにしました。組み込みモジュールとしてユーザーコードに公開されます。
私の問題は、GTKがスレッドを制御することによって機能することです。C関数g_application_run
を呼び出すと、スレッドはGTK内で無限のリスニングループに入ります。
なぜこれが問題なのですか?このGTKループで「スタック」している間、インタープリターのバイトコード解釈ループがフリーズするためです。デモ用の擬似バイトコード:
0 SOME OPCODE
1 SOME OTHER OPCODE
2 OPCODE INVOKING GTK WRAPPER FUNCTION <-- GTK invoked in C level and enters an endless loop
3 MORE OPCODES <-------- This is never executed
これに対抗するために最初に考えたのは、GTKラッパーを、Cライブラリの使用方法に合わせて「1:1ミラーリングに近い」スタイルで設計することでした。たとえば、擬似コードでは:
import gtk
func app_code() {
# ... app code ...
}
gtk.application_run(app_code)
これでおそらく問題が解決します。g_application_run
内でGTKエンドレスループを終了しないように気を付けてください。自分のユーザーコードを呼び出す責任があるからです。
これが機能しない理由:インタープリター内でユーザー関数を呼び出す方法は、
GTKラッパーはステップ1と2を簡単に実行できます。ただし、GTK無限ループ内でスタックしているため、ステップ3は決して発生しません。インタープリターループが新しい反復を開始することはありません。
だから私の質問は:この問題を解決するための可能なオプションは何ですか?できれば、この問題が既存のプロジェクトでどのように処理されるかの例は何ですか?
c関数g_application_runを呼び出すと、スレッドはGTK内で無限の待機ループに入ります。
それは起こることのほんの一部です。ここで最初に行う必要があるのは、たとえばg_signal_connect
を使用して、イベントのコールバックを登録することです。これにより、GTKがそれらを呼び出します(最初、プログラムの開始時、または後で、マウスボタンを押すなどのユーザーアクションが発生したとき)行事)。これらのコールバックはC関数である必要がありますが、おそらくこれらの呼び出しを独自のインタープリタ言語で記述された関数にマッピングする必要があります。
だからここであなたがしなければならないことは
GTKにイベントを登録するために、いくつかのコマンドを言語で実装します。これらのコマンドは、g_signal_connect
などのメソッドへの実際の呼び出しをラップする必要があります。
ラッパーは、インタープリターの固定ディスパッチャーメソッドのアドレスを、gtkメソッドへの実際のコールバックとして渡す必要があります。
g_signal_connect
のdata
パラメータには、インタプリタの状態への参照を保持するオブジェクトと、プログラミング言語の関数コールバックアドレスに相当するものを含める必要があります。
これで、イベントが発生すると、GTKはそのデータオブジェクトでディスパッチャーメソッドを呼び出し、ディスパッチャーメソッドはそこから「コールバックアドレス」を取り出し、それに応じて命令ポインターを初期化し、インタープリターループを開始します。インタープリターループは、特定のイベントのコードが完全に実行されるたびに終了します。したがって、得られるのは「1つの巨大な無限インタープリターループ」ではなく、いくつかの短期間のインタープリター呼び出しです。