{"id":22767421,"url":"https://github.com/thomastrapp/signal-wrangler","last_synced_at":"2025-04-15T00:51:45.799Z","repository":{"id":51186277,"uuid":"208501056","full_name":"thomastrapp/signal-wrangler","owner":"thomastrapp","description":"Signal handler for multi threaded C++ applications on Linux","archived":false,"fork":false,"pushed_at":"2021-05-19T11:57:38.000Z","size":53,"stargazers_count":41,"open_issues_count":0,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-28T12:44:41.863Z","etag":null,"topics":["cpp","cpp17","header-only","linux","posix","pthreads","signal-handler","signals"],"latest_commit_sha":null,"homepage":"https://thomastrapp.com/blog/signal-handlers-for-multithreaded-cpp/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thomastrapp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-14T20:39:59.000Z","updated_at":"2025-03-26T20:15:12.000Z","dependencies_parsed_at":"2022-09-01T23:00:56.007Z","dependency_job_id":null,"html_url":"https://github.com/thomastrapp/signal-wrangler","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomastrapp%2Fsignal-wrangler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomastrapp%2Fsignal-wrangler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomastrapp%2Fsignal-wrangler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomastrapp%2Fsignal-wrangler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thomastrapp","download_url":"https://codeload.github.com/thomastrapp/signal-wrangler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248986279,"owners_count":21194025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp17","header-only","linux","posix","pthreads","signal-handler","signals"],"created_at":"2024-12-11T13:30:17.872Z","updated_at":"2025-04-15T00:51:45.771Z","avatar_url":"https://github.com/thomastrapp.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"Signal handler for multi threaded C++ applications on Linux\n===========================================================\n\nSignal handler that uses [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html) and [sigwait](http://man7.org/linux/man-pages/man3/sigwait.3.html).\n\n\n## Dependencies\n\n* C++17\n* Clang or GCC\n* linux\n* pthread\n* cmake (recommended, but optional)\n* Catch2 for testing\n\n\n## Example usage\n\n```C++\n{\n  // Block signals\n  sgnl::SignalHandler signal_handler({SIGINT, SIGTERM});\n\n  // Wait for a signal\n  int signal_number = signal_handler.sigwait();\n\n  // Or, pass a handler\n  auto handler = [](int signum) {\n    if( signum == SIGINT )\n      // continue waiting for signals\n      return false;\n    if( signum == SIGTERM )\n      // stop waiting for signals\n      return true;\n  };\n\n  int last_signal = signal_handler.sigwait_handler(handler);\n} // signals are unblocked again\n```\n\nUsing a condition variable to shutdown all threads:\n\n```C++\n#include \u003csgnl/AtomicCondition.h\u003e\n#include \u003csgnl/SignalHandler.h\u003e\n\n#include \u003ccstdlib\u003e\n#include \u003cfuture\u003e\n#include \u003ciostream\u003e\n#include \u003cthread\u003e\n\n\nvoid Worker(const sgnl::AtomicCondition\u003cbool\u003e\u0026 exit_condition)\n{\n  auto predicate = [\u0026exit_condition]() {\n    return exit_condition.get();\n  };\n  while( true )\n  {\n    exit_condition.wait_for(std::chrono::minutes(1), predicate);\n    if( exit_condition.get() )\n      return;\n    /* ... do work ... */\n  }\n}\n\nint main()\n{\n  sgnl::AtomicCondition\u003cbool\u003e exit_condition(false);\n\n  auto handler = [\u0026exit_condition](int signum) {\n    std::cout \u003c\u003c \"received signal \" \u003c\u003c signum \u003c\u003c \"\\n\";\n    if( signum == SIGTERM || signum == SIGINT )\n    {\n      exit_condition.set(true);\n      // wakeup all waiting threads\n      exit_condition.notify_all();\n      // stop polling for signals\n      return true;\n    }\n\n    // continue waiting for signals\n    return false;\n  };\n\n  // Block signals in this thread.\n  // Threads spawned later will inherit the signal mask.\n  sgnl::SignalHandler signal_handler({SIGINT, SIGTERM, SIGUSR1});\n\n  std::future\u003cint\u003e ft_sig_handler =\n    std::async(\n        std::launch::async,\n        \u0026sgnl::SignalHandler::sigwait_handler,\n        \u0026signal_handler,\n        std::ref(handler));\n\n  std::vector\u003cstd::future\u003cvoid\u003e\u003e futures;\n  for(int i = 0; i \u003c 10; ++i)\n    futures.push_back(\n        std::async(\n          std::launch::async,\n          Worker,\n          std::ref(exit_condition)));\n\n  // SIGUSR1\n  std::this_thread::sleep_for(std::chrono::milliseconds(100));\n  kill(0, SIGUSR1);\n\n  // SIGTERM\n  kill(0, SIGTERM);\n  std::this_thread::sleep_for(std::chrono::milliseconds(100));\n\n  for(auto\u0026 future : futures)\n    future.wait();\n\n  int last_signal = ft_sig_handler.get();\n  std::cout \u003c\u003c \"exiting (received signal \" \u003c\u003c last_signal \u003c\u003c \")\\n\";\n\n  return EXIT_SUCCESS;\n}\n```\n\n\n## Build \u0026 Install\n\n```SH\nmkdir -p build/ \u0026\u0026 cd build/\ncmake ..\n# build and run tests\nmake sgnl-test \u0026\u0026 ./test/sgnl-test\n# build and run example\nmake example \u0026\u0026 ./example\n# install headers and CMake config\nmake install\n```\n\n## Using signal-wrangler with CMake\n\nThe easiest way to add signal-wrangler to a CMake project is by using\n[FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):\n\n```CMAKE\ncmake_minimum_required(VERSION 3.14 FATAL_ERROR)\nproject(my-example)\n\ninclude(FetchContent)\nFetchContent_Declare(\n  signal-wrangler\n  GIT_REPOSITORY https://github.com/thomastrapp/signal-wrangler\n  GIT_TAG v0.4.0)\nFetchContent_MakeAvailable(signal-wrangler)\n\nadd_executable(my-example \"example/example.cpp\")\ntarget_link_libraries(my-example sgnl::sgnl)\n```\n\nOr, by installing signal-wrangler (`make install`) and using `find_package`:\n\n```CMAKE\nfind_package(Sgnl REQUIRED)\ntarget_link_libraries(my-project sgnl::sgnl ...)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomastrapp%2Fsignal-wrangler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomastrapp%2Fsignal-wrangler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomastrapp%2Fsignal-wrangler/lists"}