2012-10-12 30 views
5

私は無限ループでいくつかの作業をするオブジェクトを持っています。 main()はオブジェクトをインスタンス化し、run()メソッドを呼び出します。私はスレッドを使いたくないので、私はオブジェクトの実行を止めるための解決策が必要です。あなたの下に、私が思いついたものが見えます。シグナルをキャッチする:シグナルハンドラとしてメンバ関数を使用する

struct Foo 
{ 
    void run() 
    { 
     running = 1; 
     while (running) 
      do_something_useful(); 

     std::cout << "Execution stopped." << std::endl; 
    } 

    bool running; 

    void catch_signal(int signal) 
    { 
     std::cout << "Caught signal " << signal << std::endl; 
     if(signal == SIGTERM) 
      running = false; 
    } 

}; 

ご覧のとおり、信号を非同期で送信する必要があります。したがって、私はシグナルハンドラとsigactionを使用します。 mainの下に私は使用すると想像することができます。私は今、何を期待する

int main(int argc, char** argv) 
{ 
    Foo foo; 
    struct sigaction sigIntHandler; 

    boost::function< void (int) > f; 
    f = std::bind1st(
     std::mem_fun(&Foo::catch_signal), &foo); 
    f(5); // this call works 

    sigIntHandler.sa_handler = f;   // compiler complains, "cannot assign ..." 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 
    sigaction(SIGTERM, &sigIntHandler, NULL); 
    s.run(); 

} 

:私がキャッチされ、私のオブジェクトは、反復処理を停止し、メインに戻ることになりますSIGTERMを送信するまでプログラムが実行されます。

私は今、2つの質問があります

(A)あなたは「コンパイラが文句を言う」とマークされた行を参照してくださいコードでは、メッセージが私が作るように変更しなければならないのは何

boost::function<void(int)> cannot be converted to __sighandler_t {aka void (*)(int)} 

のようなこの作品?私はfvoid f(int)のようで、信号ハンドラがいくつかの例で得られる関数と似ていると思います。

(b)「その男は何をしていますか?」と思っている人のために:この種のものをより良く解決する方法についてアドバイスをしていますか?

+0

ちょうど好奇心から、なぜあなたはスレッドを使いたくないですか?私はブーストをまったく使用していませんが、私の前提では、コールバック関数が提供されることを期待しています。 – M4rc

+0

スレッド内で '' Foo :: run() ''を起動し、 '' main''でシグナルを捕捉し、メインコールをsthにします。 '' thread.terminate() ''のように?はい、可能性はありますが、これはあまりにも多いと思いました。 –

+0

それは確かに一つの方法です。もう1つは(私の鎮静化した思考の中で)、あなたが必要とする情報を持つ構造体をスレッドとして登録することができるので、通常のメイン関数をループして実行するシグナルハンドラそれが自分のスレッドであれば、値byrefを取得してイベントが発生したかどうかを確認し、そうであればどのようなイベントと適切なレスポンスを返します。 – M4rc

答えて

7
  • これを行うには何を変更する必要がありますか?私は、シグナルハンドラがいくつかの例で得られる関数のように、fがvoid f(int)のようであると考えます。

コンパイラがタイプ文句を言うので、あなたが関数ポインタではなく、タイプboost::function<void(int)>のオブジェクトを渡す必要があります。このタイプのグローバル変数を作成し、このオブジェクトは働くだろう呼び出す関数追加:

boost::function<void(int)> myCb; 
void CallCb(int value) 
{ 
    myCb(value); 
} 

int main(int argc, char** argv) 
{ 
    Foo foo; 
    struct sigaction sigIntHandler; 

    myCb = std::bind1st(
     std::mem_fun(&Foo::catch_signal), &foo); 
    f(5); // this call works 

    sigIntHandler.sa_handler = CallCb; 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 
    sigaction(SIGTERM, &sigIntHandler, NULL); 
    s.run(); 

} 
  • をあなたはより良いこの種のものを解決するためにどのように何かアドバイスはありますか?

実際にはありません。アイデアは大丈夫​​です。私はちょうどC++ 11ラムダに代わります

+1

特に「f」は関数ではなく、私が考えなかったオブジェクトであることを指摘してくれてありがとう。 –

+0

C++ 11ラムダでどのように実行するのか、例を挙げてください。 – Azmisov

2

シグナルハンドラで移植可能なことはごくわずかです。基本的には、タイプがsig_atomic_tのオブジェクトに値を格納できます。たとえば、coutに挿入する必要はありません。 C++ 11を使用している場合は、原子型や明示的なフェンスを使用してもう少し多くのことを行うことができますが、標準ライブラリへの他の呼び出しでは、賢明なことをする必要はありません。

あなたができることは、関数(自由な関数または静的メンバー関数のどちらかを書くことです(ただし、C++リンケージで微妙な問題があります:正式に静的メンバー関数は動作しません実際には常にそうです))、メンバー関数を呼び出し、runningfalseに設定します(runningのタイプをsig_atomic_tに変更したと仮定します)。

関連する問題