Python スクリプトを中止しようとすると問題が発生します。たとえば、次のようになります。
#!/usr/bin/python
import hello
hello.draw()
exit()
draw() は C 関数です。この関数には、テキストを出力するためのループがあります。CTRL-C で抜けようとしましたが、うまくいきません。重要なことは、C コードは変更できないということです。
何か案は?
これを行う方法の例をまとめました。関数を拡張し、変更することなく関数から逃れることができます。たとえば、関数foo
(テスト用に test.h でインライン化されていた) が与えられた場合:
void foo() {
while(1); // never returns
}
信号と でゲームをプレイできますsiglongjmp
。ただし、安全な非同期関数のみを 内から呼び出すようにするか、安全でない呼び出しの前にシグナルをマスクし、後でマスクを解除するように十分に注意する必要があることに注意してください。foo
次に、関数をラップし、%exception
追加のコードを挿入してシグナルが関数をバックアウトできるようにします。
%module test
%{
#include <setjmp.h>
#include <signal.h>
static sigjmp_buf timeout;
static void backout(int sig) {
siglongjmp(timeout, sig);
}
#include "test.h"
%}
%include <exception.i>
%exception {
if (!sigsetjmp(timeout, 1)) {
signal(SIGALRM,backout); // Check return?
$action
}
else {
// raise a Python exception
SWIG_exception(SWIG_RuntimeError, "Timeout in $decl");
}
}
void foo();
%exception;
これにより、次のように書くことができます。
import signal
import test
signal.alarm(5)
test.foo()
非同期セーフ関数に関する警告を考えると、これは期待どおりに機能します。ここで使用SIGALRM
したのは、すべてを 1 つの Python ファイル内に自己完結型に保つことができるためです。必要に応じて、別のスレッド/プロセスやその他のシグナルを使用できます。
私の例で SIGALRM を SIGINT に変更すると (そして明らかに SIGALRM を発生させないでください) Ctrl+Cで動作します。Python が使用するデフォルト ハンドラーは、基になる呼び出しが Python に制御を返した後に、単純にフラグを設定してシグナルを処理します。これにより、非同期安全性の問題全体がうまく回避されます。
C 関数にそれを中止する方法を与える必要があります。たとえば、描画ループでグローバル ステータス フラグをポーリングできます。