Using Auto and Lambda to handle Signal?

僤鯓⒐⒋嵵緔 提交于 2019-12-04 16:29:57

问题


I have written this program that has a main function, inside which, I am creating two sockets, like this:

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

Now I do some stuff with them, and when the user presses Ctrl+C to terminate the process, I want to make sure the sockets close properly, so I do this:

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

But this throws the following compilation error when compiled as 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)’

Is it not possible to use lambda this way to handle signals? Please advise.

P.S. I know I could put that in a destructor, if I did proper OOP, but I am curious to see if this works.


回答1:


You cannot use the capture feature from lambda when calling a simple function pointer. The standard states that a lambda function without a capture is convertible to a function pointer, though:

5.1.2 (6) The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

For instance, this works:

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

But not this:

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

You could actually keep sockfd1 and sockfd2 as global variables and then, you could use them in the lambda function. But that is clearly not a good design. So it is better to use a RAII design. And if the program is terminated the sockets will be closed anyway (as @Dani is pointing out).




回答2:


A little late but if someone needs such a solution one can use std::function as a wrapper to hold a lambda capable of capturing variables:

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



回答3:


Sockets will always be closed when a program is closed, no need to worry about it.
If you worry about logical resource handling, put it in destructors, but those won't be called when the user presses CTRL-C



来源:https://stackoverflow.com/questions/11468414/using-auto-and-lambda-to-handle-signal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!