Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using sigwait with std::thread and pipe

Consider a parallel program that consists of a number of worker threads. These threads have a poll-loop on some file descriptors. The program is supposed to run until ctrl-c is hit / the process receives a SIGINT. The program should never wake up unnecessarily.

I have devised the following combination of sigwait, std::thread, pipe and pthread_sigmask. Note that in the actual application, there are more file descriptors, hence I am not using atomics for shutting down the threads.

#include <thread>
#include <iostream>
#include <cstdlib>
#include <csignal>

extern "C" {
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
}

int fds[2];

void thread_run() {
    struct pollfd pfd = {fds[0], POLLIN, 0};
    int ret = poll(&pfd, 1, -1);
    if (ret != 1) std::terminate();
    if (!pfd.revents & POLLIN) std::abort();
}

int main()
{
    int ret = pipe(fds);
    if (ret) std::abort();

    sigset_t ss;
    sigemptyset(&ss);
    sigaddset(&ss, SIGINT);

    ret = pthread_sigmask(SIG_BLOCK, &ss, NULL);
    if (ret) std::abort();

    std::thread t(thread_run);

    int sig;
    ret = sigwait(&ss, &sig);
    if (ret) std::abort();

    char b = 0;
    ret = write(fds[1], &b, 1);
    if (ret != 1) std::abort();

    t.join();

    close(fds[0]);
    close(fds[1]);
}

The program appears to work without any issues.

  1. Is this approach conforming or am I overlooking any caveats?
  2. Are there any specific error cases that might occur in regular operation and can be handled more gracefully?
  3. Would the program be still correct if i swap std::thread-creation and pthread_sigmask?
like image 796
Zulan Avatar asked May 31 '26 11:05

Zulan


1 Answers

  1. This is a standard recommended approach and it works well. See examples section in pthread_sigmask.
  2. Cannot spot any.
  3. It would not be correct. Most signals are process-specific, which means they get delivered to any thread in the process that does not block that signal. Hence, that signal must be blocked in all threads but the one that handles the signal.

You may like to use std::abort call for unexpected situations. std::terminate is called by the C++ runtime when exception handling fails.

like image 77
Maxim Egorushkin Avatar answered Jun 02 '26 00:06

Maxim Egorushkin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!