Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Auto and Lambda to handle Signal?

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.

like image 690
Subhamoy S. Avatar asked Jul 13 '12 10:07

Subhamoy S.


2 Answers

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).

like image 65
betabandido Avatar answered Oct 21 '22 19:10

betabandido


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();
}
like image 44
Michael Haidl Avatar answered Oct 21 '22 18:10

Michael Haidl