【问题标题】:Using Auto and Lambda to handle Signal?使用 Auto 和 Lambda 处理信号?
【发布时间】:2012-07-13 10:10:02
【问题描述】:

我编写了这个程序,它有一个 main 函数,在其中,我创建了两个套接字,如下所示:

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 来处理信号吗?请指教。

附:我知道如果我做了正确的 OOP,我可以把它放在析构函数中,但我很想知道这是否有效。

【问题讨论】:

  • 虽然这肯定对你没有帮助,但如果将来其他人可能需要使用 std::signal 但面临这个问题,并且可以在代码库中正式使用 Asio,那么 Asio 支持这个.

标签: c++ lambda c++11 signals posix


【解决方案1】:

在调用简单函数指针时,您不能使用 lambda 的捕获功能。标准规定,没有捕获的 lambda 函数可以转换为函数指针:

5.1.2 (6) 没有 lambda-capture 的 lambda-expression 的闭包类型有一个 public non-virtual non-explicit const 将函数转换为指向与闭包类型具有相同参数和返回类型的函数的指针 函数调用运算符。这个转换函数返回的值应该是函数的地址 这在调用时与调用闭包类型的函数调用运算符具有相同的效果。

例如,这是可行的:

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

但不是这个:

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

您实际上可以将 sockfd1sockfd2 保留为全局变量,然后您可以在 lambda 函数中使用它们。但这显然不是一个好的设计。所以最好使用RAII 设计。而且,如果程序终止,则无论如何都会关闭套接字(正如@Dani 指出的那样)。

【讨论】:

    【解决方案2】:

    有点晚了,但如果有人需要这样的解决方案,可以使用 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();
    }
    

    【讨论】:

    • 如果在将 lambda 分配给 shutdown_handler 之前发生 SIGINT (Ctrl+C),这将终止程序并带有 bad_function_call 类型的未捕获异常。
    • @Bulletmagnet 是的,你是对的。如果在调用前检查会更好,例如:if (shutdown_handler)
    【解决方案3】:

    当程序关闭时,套接字总是会关闭,无需担心。
    如果您担心逻辑资源处理,请将其放入析构函数中,但是当用户按下 CTRL-C 时不会调用这些析构函数

    【讨论】:

    • 没错,但它们不会立即关闭(最多几秒钟)。如果你连续两次快速运行一个程序,对于绑定到特定端口的套接字,你会得到一些关于套接字无法绑定的错误。
    猜你喜欢
    • 1970-01-01
    • 2017-08-29
    • 1970-01-01
    • 2014-01-08
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多