2012-07-13 50 views
10

我寫了這個程序,有一個主要功能,在其內部,我創建了兩個插槽,這樣的:使用Auto和Lambda來處理信號?

int sockfd1 = socket(AF_INET, SOCK_STREAM, 0); 
int sockfd2 = socket(AF_INET, SOCK_STREAM, 0); 

現在我做一些東西與他們,當用戶按下CTRL + C終止這個過程中,我想確保插座正常關閉,所以我這樣做:

auto sigTermHandler = [&] (int param) { close(sockfd1); close(sockfd2); }; 
signal(SIGTERM, sigTermHandler); 

但是,這將引發當作爲g++ -std=gnu++0x <filename>.cpp編譯以下編譯錯誤:

error: cannot convert ‘main(int, char**)::<lambda(int)>’ to ‘__sighandler_t {aka void (*)(int)}’ for argument ‘2’ to ‘void (* signal(int, __sighandler_t))(int)’ 

用這種方法來處理信號不可能使用lambda嗎?請指教。

P.S.我知道我可以把它放在析構函數中,如果我做了適當的OOP,但我很好奇,看看它是否有效。

回答

15

調用簡單函數指針時,不能使用lambda中的捕獲功能。該標準狀態,如果沒有捕獲lambda函數可轉化爲一個函數指針,雖然:

5.1.2(6),用於與無λ-捕獲的λ-表達的閉合類型有一個公共非虛非顯式const 轉換函數指向具有與閉包類型的 函數調用運算符相同的參數和返回類型的函數。此轉換函數返回的值應爲函數 的地址,該函數在調用時具有與調用閉包類型的函數調用操作符相同的效果。

舉例來說,這個工程:

signal(SIGTERM, [](int signum) { /* ... */ }); 

但不是這樣的:

signal(SIGTERM, [foo](int signum) { /* use foo here */ }); 

其實你可以保持sockfd1sockfd2爲全局變量,然後,你可以在lambda使用它們功能。但這顯然不是一個好設計。所以最好使用RAII設計。如果程序終止,套接字將被關閉(正如@Dani指出的那樣)。

0

程序關閉時,套接字將始終關閉,無需擔心。
如果擔心邏輯資源處理,把它放在析構函數,但這些不會被調用,當用戶按Ctrl-C

1

晚了一點,但如果有人需要這樣的解決方案可以使用std::function作爲包裝舉行能夠捕捉變量的lambda:

#include <functional> 
#include <iostream> 

namespace { 
std::function<void(int)> shutdown_handler; 
void signal_handler(int signal) { shutdown_handler(signal); } 
} // namespace 

int main(int argc, char *argv[]) { 
    std::signal(SIGINT, signal_handler); 
    MyTCPServer server; 
    shutdown_handler = [&](int signal) { 
    std::cout << "Server shutdown...\n"; 
    server.shutdown(); 
    }; 
    server.do_work_for_ever(); 
}