1

I have a C++ thread (Linux) that uses blocking read to get data on some IO interface. I want to be able to abort read, and exit the thread.

Here https://stackoverflow.com/a/51742996/16317303 the general principle is explained, using pthread_kill to send a signal to a specific thread that interrupts the blocking read.

However, when I implement it that way, I am missing the "sending signal to specific thread" part. For example, CTRL+C in terminal does trigger the same handler as pthread_kill does, meaning that CTRL+C is not ending the console application anymore. For me it seems like a global handler for any SIGINT, and I don't know how I can make it that way that only this specific thread receives the signal and takes action, otherwise, when I use this pattern for different threads, I can't distinguish which thread receives a signal.

sctty
  • 55
  • 5
  • what is the data source? a socket? – user253751 Jan 11 '23 at 14:18
  • You might want to reread `pthread_kill`'s manual page. – Sam Varshavchik Jan 11 '23 at 14:19
  • Usually it is done by sending an abort signal from another thread for example, so that the blocking read will exit, instead of killing the thread (I saw that mechanisms for sockets but it was a long time ago, I don't remember the details) So it implies that the read function is blocking on something you can control (a flag, etc...). – Fareanor Jan 11 '23 at 14:20
  • 3
    It depends how the thread is blocked. If it is blocked on file descriptor then use another descriptor, e.g. created with `signalfd()` or `eventfd()` or `pipe()` and wait on both, e.g. with `poll()`. If it is blocked by `pthread_cond_wait()` then check termination flag and signal cond var as flag is set. Use both methods if thread may block on any of these calls. – dimich Jan 11 '23 at 14:33
  • @SamVarshavchik I guess you wanted me to read the first paragraph beneath Notes, so I understand pthread_kill is not what helps me to archieve my goal – sctty Jan 11 '23 at 18:03
  • @user253751 the data source is a device in /dev/input – sctty Jan 11 '23 at 18:04
  • 1
    No, just the first sentence, in the first paragraph. You asked about "sending signal to specific thread". And that happens to be precisely the description of `pthread_kill`, as given by the very first sentence. – Sam Varshavchik Jan 11 '23 at 18:06

3 Answers3

1

Signal handlers are indeed global.

As you observed, when a signal is generated for a process (as by kill or Ctrl+C), rather than for a specific thread (as by pthread_kill or a floating point exception), the OS simply chooses one thread of that process to receive the signal. (Ref. POSIX.1-2017 Signal Concepts)

You can influence this choice by blocking (masking) the signal in all threads except the special one you want to receive the signal. Since thread signal masks are inherited, a typical approach is to mask the signal straight away in main() with pthread_sigmask(SIG_BLOCK, ...), and then to unmask it (SIG_UNBLOCK) in your special thread.

But this is a dubious approach. SIGINT seems the wrong signal to use, since it has well-established semantics — I expect a Ctrl+C to terminate the foreground process group! Moreover, I/O multiplexing with a "notification fd," as others have suggested, is cleaner and less error-prone.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
1

It's usually easier if you avoid signals as much as possible.

Instead of doing a blocking read, you can make the file-descriptor non-blocking, then use poll (which is blocking) to wait for several things at the same time. You can make it wait for input data and wait for the shutdown signal at the same time. It returns if either one happens, and tells you which one happened.

To make this work, the shutdown signal has to be something you can read data from, like a pipe or (as sctty suggested) an eventfd. When you write to the other end of the pipe, poll returns, saying "hey, you can read data from the pipe now!" but you don't want to actually read data from it, you just want to shut down (and close the pipe) when that happens.

user253751
  • 57,427
  • 7
  • 48
  • 90
0

See @dimich comment on the question. I use eventfd() and poll() to achieve the desired behavior, the man pages provide ready to use sample code.

sctty
  • 55
  • 5
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 12 '23 at 08:46