2012-07-13 19 views
10

Tôi đã viết chương trình này có một chức năng chính, trong đó, tôi đang tạo ra hai ổ cắm, như thế này:Sử dụng Tự động và Lambda để xử lý tín hiệu?

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

Bây giờ tôi làm một số thứ với họ, và khi người dùng nhấn tổ hợp phím Ctrl + C để chấm dứt quá trình này, tôi muốn chắc chắn rằng các ổ cắm đóng đúng cách, vì vậy tôi làm điều này:

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

Nhưng điều này ném lỗi biên dịch sau khi biên dịch như 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)’ 

Không thể sử dụng lambda theo cách này để xử lý tín hiệu? Xin cho biết.

P.S. Tôi biết tôi có thể đặt nó trong một destructor, nếu tôi đã làm đúng OOP, nhưng tôi tò mò để xem nếu điều này hoạt động.

Trả lời

15

Bạn không thể sử dụng tính năng chụp từ lambda khi gọi một con trỏ hàm đơn giản. Các tiêu chuẩn nói rằng một hàm lambda mà không có một nắm bắt được chuyển đổi thành một con trỏ hàm, mặc dù:

5.1.2 (6) Kiểu đóng cửa cho một biểu thức lambda không có lambda-capture có một công chúng không ảo không rõ ràng const chức năng chuyển đổi để con trỏ đến chức năng có cùng tham số và kiểu trả về như là toán tử gọi hàm của loại đóng. Giá trị trả về bởi hàm chuyển đổi này sẽ là địa chỉ của hàm , khi được gọi, có cùng tác dụng như gọi toán tử gọi hàm của loại đóng.

Ví dụ, công trình này:

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

Nhưng không này:

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

Bạn thực sự có thể giữ sockfd1sockfd2 như biến toàn cục và sau đó, bạn có thể sử dụng chúng trong các lambda chức năng. Nhưng đó rõ ràng không phải là một thiết kế tốt. Vì vậy, tốt hơn là sử dụng thiết kế RAII. Và nếu chương trình được chấm dứt các ổ cắm sẽ được đóng lại anyway (như @ Dani chỉ ra).

0

Ổ cắm sẽ luôn đóng khi chương trình đóng, không cần phải lo lắng về nó.
Nếu bạn lo lắng về việc xử lý tài nguyên hợp lý, đặt nó trong hàm hủy, nhưng những người sẽ không được gọi khi người dùng nhấn tổ hợp phím CTRL-C

1

Một chút muộn nhưng nếu ai đó cần một giải pháp như vậy người ta có thể sử dụng như là một wrapper std::function để giữ một lambda có khả năng nắm bắt các biến:

#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(); 
}