2012-10-12 80 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它被捕獲並會導致我的對象停止迭代並返回主菜單。

我現在有兩個問題:

(一)在你看到標有「編譯器抱怨」一行代碼,消息就像

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

什麼我需要改變,以使這項工作?我認爲f就像void f(int),就像信號處理程序在某些示例中獲得的功能一樣。

(b)對於那些想知道「那個人在幹什麼?」的人:你有什麼建議可以更好地解決這種問題嗎?

+0

出於好奇,爲什麼你不想使用線程?雖然我根本沒有使用boost,但我的假設是期望提供一個回調函數。 – M4rc

+0

就像在線程中啓動''Foo :: run()''一樣,在main函數中捕獲信號並讓主函數調用。像''thread.terminate()''?是的,會是一種可能性,但我認爲這樣做太多了。 –

+0

這是確定的一種方法。另一個(在我思考的沉悶mi)中)是,你可以擁有一個結構,包含你需要的任何信息,把它註冊爲一個線程,所以你用它的正常主函數運行循環,並且運行信號處理程序在它自己的線程上,那麼你只需抓取值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 lambda來代替

+1

特別感謝您指出''f''不是一個函數,而是一個我沒有想到的對象。 –

+0

你能舉一個例子說明如何用C++ 11 lambda來做這件事嗎? – Azmisov

2

在信號處理程序中,你可以做的很少。基本上,您可以將值存儲在類型爲sig_atomic_t的對象中。例如,插入cout不必工作。如果你有C++ 11,你可以使用原子類型或明確的屏蔽來做更多的事情,但是對標準庫的任何其他調用並不需要做任何明智的事情。所以,你所能做的就是編寫一個函數(一個自由函數或一個靜態成員函數(但在C++鏈接中存在一個微妙的問題:形式上靜態成員函數將不起作用,但實際上它總是)),它調用成員函數,該函數依次將running設置爲false(假設您已將running的類型更改爲sig_atomic_t)。