2011-02-27 5 views
3

私のコードのセクションを実行したいが、完全に終了する前に割り込み(ctrl-c)するオプションを付けて、残りのコードの実行を再開する。 (私はLinuxプラットフォームで作業しています)メソッドを中断してもコードの残りの部分を実行し続ける

私の推測では、フォークを作成してメソッドを呼び出し、シグナルハンドリングを使用します。信号処理にはどのようなステップが必要ですか?

void Manager::Run() 
{ 
    pid_t pID = fork(); 

    if(pID<0) 
     exit(1);//give up here 
    else if(pID==0) {    
     BuildList(); //I'd like the option to ctrl-c this only 
     //some code here catch user signal interrupt? 
    } 
    else {;} 

    waitpid(pID,NULL,0);//pause until BuildList() is done or interrupted 


    PrintList(); 
} 

if/else部分のどこかにシグナル(SIGINT、sigint)のような行を使いたいと思うようです。そして、私はこのような関数を定義する必要があります:

sigint(int param){ signal(param, SIG_DFL);}; 

私は子プロセスを殺すしかありません。

これは私の問題を解決する正しい考えですか?もしそうなら、この作業にはどのような信号処理が必要ですか?

UPDATE:
より完全に私の質問に対処するために、私が提案した非フォーク方法を検討しました。私はフォークなしでこれを行うことができるはずです。残念ながら、私はいくつかの試みからコンパイルエラーに悩まされています。私は更新されたコードと新しいエラーを含んでいます。

Manager.hh

static void sighandler(int signum) 
    { 
     PrintList(); 
     exit(1); 
    }; 

sighandler機能は、私はこれを取得静的でない場合Manager.ccは

void Manager::Run() 
{ 
    signal(SIGINT,sighandler);//sets up sighandler() 
    BuildList(); //add elements to a list 
    signal(SIGINT,SIG_DFL); //restore default 
    PrintList(); 
} 

が含まれています:Managerでコールsignal(SIGINT,sighandler)
error: argument of type 'void (Manager::)(int)' does not match 'void (*)(int)'
を:: Run()を実行してハンドラを設定します。

私は静的sighandler機能で、私はこの取得がprintlist()を呼び出す場合:sighandlerにPrintList();コールに
error: cannot call member function 'void Manager::PrintList()' without object
を()。

最後に、PrintList()を静的関数(static sighandlerを使用)にすると、Listおよびiteratorでこれらのエラーが発生し、リストをステップ実行することに注意してください。
error: invalid use of member 'Manager::theList' in static member function
error: invalid use of member 'Manager::it' in static member function

これらのエラー周りの任意の巧妙な方法?

+1

私は信号の問題を別の質問にするべきだと思います。元の質問への回答を受け入れると、回答が得られる可能性が高くなります。 –

答えて

2

中断したい機能によっては、これをフォークせずに実装することができます。

関数がループで処理する場合、シグナルハンドラは、処理を停止することを示すブール値を設定できます。ループはこのブール値をチェックするだけで、シグナルハンドラによって一度設定されると、関数は安全かつ一貫性のある状態で終了することができます。

+0

良い点 - 私の答えは、他の理由で複数のプロセス(またはスレッド)が必要だったと仮定していますが、割り込みの場合のみ、シグナルハンドラとグローバルブールがはるかに簡単です。 –

+0

ありがとう、私は誤って私がフォークが必要だと思うように自分自身を確信していた。 – niwals

2

明示的にメモリを共有していない場合(mmapなど)、forkの子は、表示されている結果を生成しません。あなたはそれを修正したと仮定するとsignal(SIGINT, SIG_IGN)で、親のctrl-Cを無視して(forkの前に)、signal(SIGINT, SIG_DFL)という子のデフォルトに戻すことができます。

あなたの代わりにスレッドを使用した場合、その後の回答の変更(共有メモリsimpilfyする):SIGINTが、それは対照的に(特定のスレッドに命令の実行に起因しないという意味、非同期信号であるが、SIGSEGVです同期信号)。スレッド型アプリケーションでは、すべてのスレッドに対して1つの共有シグナルハンドラがあります。非同期シグナルの場合は、スレッドのいずれかに渡すことができます。そのハンドラは内部変数BuildList()の変数を可視に設定する必要があるため、正常に終了することができます。

無視してください。SIGINTあなたはアプリケーション全体を強制終了したいと思っていて、今はctrl-Cは何もしません。避けられないことに、私はそれらを殺すための他の方法を見つけるようなアプリケーションを呪っていることが分かります(Ctrl + \ SIGQUIT、またはCtrl-Z + killを送る)。

+0

"そのハンドラは、いくらかの変数をBuildList()の内部ループに見えるように設定して、正常に終了できるようにする必要があります。"この方法でスレッドを使用している場合は、シグナルハンドラから 'pthread_cancel'を使用し、内側のループで' pthread_testcancel'を使用して、独自のメカニズムを使用しないでください。私は 'pthread_cancel'はシグナルセーフではないと思っています。それは非常に大きな*メカニズムではないと思います。 –

+0

あなたは、BuildList()でリソースをリークさせたくないのですが、メモリを割り当てる関数のように思えます。キャンセル可能性タイプを 'PTHREAD_CANCEL_DEFERRED'に設定したとしても、明示的な' pthread_testcancel'の他にいくつかのキャンセルポイントがあります。これを回避する方法があるかもしれません - 私は 'pthread_cancel'を玩具のアプリケーションの外にはあまり使っていません。 –

+0

かなり十分ですが、 'malloc'にはキャンセルポイントが含まれていないので、実際にはこのリストがどのように構築されるかによって異なります。一般的に、これらの他のキャンセルポイントは長い時間をブロックするものなので、cancel-on-timeoutのためにそこに*置いておきます。フラグがセットされているとブロックしていると、フラグが不十分である可能性があります。私はスレッドのキャンセルは、落とし穴を含めて適切にそれらを学ぶまで使用する価値のないものの1つかもしれないと思う、それは意味をなさない。私はあなたのロギングをオンにすることによって、キャンセル可能なコードに誤ってキャンセルポイントを導入することができることを思い出しています。 –

関連する問題