C++ RAII at the process-level

C++ RAII at the process-level

Problem: Your application is a webserver with an associated ODBC connection pool (per-process pool), you want to intercept process termination/interruption signals and use a Lambda function as a callback, in order to release resources and stop the webserver properly. You can't, std::signal won't accept a Lambda, and you want a Lambda because the webserver is a local variable in main() and you don't want to use global variables and an external signalHandler() function, you want everything solved within the scope of main() and using the capture features of a C++ Lambda.

The solution? a simple C++ struct than can be encapsulated in a header file, serves as an indirect way to allow the use of a Lambda defined in main(). Here it is:

No alt text provided for this image

We confront another limitation, a struct's member function cannot be used as a function pointer for std::signal, not even with the help of std::mem_fn, but a struct's static function can be used for std::signal, that's why have to play with "static" in all cases for our simple struct.

This limitation is very well explained here, by Bjarne Stroustrup (my guess):

Back to our design, a static init(...) function replaces a normal constructor because we need to access a static variable signalHandlerFunc, which will contain a reference to a Lambda that represents a std::function<void(int)>. In turn, std::signal will use our static callback signalHandler(), which is acceptable as a function pointer for this system call, and this function wraps the reference to the Lambda (which cannot be passed as a pointer to std::signal), that's all the generic mechanism. The program using this code does not know about the signals intercepted, it only cares about the tasks to be executed inside the Lambda, and this struct does not know about the Lambda, it only serves the purpose of encapsulation, registering the signals and invoking the lambda if a signal gets intercepted.

The client code using this simple component

No alt text provided for this image

At startup, the ODBC pool is initialized with odbcInit() as well as the HTTPS web server, right after that, we want to register the signal handler using a Lambda, we can do it using our struct SignalManager and its static function init(), which receives the Lambda function, we will release the ODBC pool and stop the webserver and its threads, after that, a clean exit.

SignalManager registers 2 commonly used signals on Windows and Linux, SIGINT and SIGTERM, which is enough for CTRL-C, Windows service stop, and Linux kill (with default value or SIGTERM). If we decide to intercept more signals in the future, the main() client code won't be affected, the same for the SignalManager component, it does not care about the contents of the Lambda, it's only task is to execute it on a signal interception.

It's (according to me!) a process-level RAAI, we acquire process-level resources at startup, like the webserver and ODBC pool, and we release them on process termination, and we do it with a clean, simple mechanism, no global variables, just plain modern C++ with a reasonable separation of concerns between the parties involved.








Charaf E.ChatBi

Exploring Equations ?? = ??(??(??))

2 年

Brilliant.

要查看或添加评论,请登录

Martín Córdova的更多文章

  • C++ Server - QuickStart with Kubernetes - Part 1

    C++ Server - QuickStart with Kubernetes - Part 1

    In a few minutes, using your Windows 10 Pro PC or Laptop, you can install and test our free C++ microservices engine…

  • QuickStart con CPPServer y Kubernetes

    QuickStart con CPPServer y Kubernetes

    Llegó la hora, hemos liberado para uso gratuito nuestro engine de microservicios en C++, este es un QuickStart para…

    2 条评论
  • Observability you said? C++? Ok

    Observability you said? C++? Ok

    CPPServer, nuestro engine de microservicios escrito en C++, pesa 300K, compilado a código nativo optimizado y lo…

  • Kubernetes-Fest en Windows 10 cortesía de Ubuntu

    Kubernetes-Fest en Windows 10 cortesía de Ubuntu

    Multipass de Canonical vino a cambiar el juego en cuanto a virtualización, y que lo haga en Windows 10 Pro es aun más…

  • Instalación express de una BD de demo con PostgreSQL y Docker

    Instalación express de una BD de demo con PostgreSQL y Docker

    Estamos próximos a liberar para uso gratuito nuestra plataforma de microservicios C++, corre en Kubernetes y en Azure…

    13 条评论
  • Renovación automática de certificados con Docker y HAProxy

    Renovación automática de certificados con Docker y HAProxy

    Los certificados SSL gratuitos con Let's Encrypt están muy de moda, obtenerlos y renovarlos son tareas que se pueden…

  • World's smallest thread pool in C++

    World's smallest thread pool in C++

    OK, the title is a trap, maybe it won't be the smallest but close I hope, I finally put the sacred red book into good…

  • Entonando acceso a la red en Docker

    Entonando acceso a la red en Docker

    Vamos a mostrar como mejorar la configuración de red de los containers Docker, sobre todo para los servidores, pero es…

  • Automatizando OCSP SSL con Docker y HAProxy

    Automatizando OCSP SSL con Docker y HAProxy

    Voy a mostrar como resolvemos la renovación automática del archivo OCSP emitido por la entidad que generó el…

  • Modern C++ vs ODBC API

    Modern C++ vs ODBC API

    Our C++ microservices platform includes a header-only library that encapsulates ODBC API in a very pragmatic way, just…

社区洞察

其他会员也浏览了