6

So I've been programming in C lately and studying Signals and POSIX threads. I know I could wait on a signal in a thread, but I've been wondering if it's possible to have a thread which contains a while loop that will keep executing forever while SIGINT is not received. So basically i'm not waiting on a signal (stopping execution of while loop) but keep executing until the signal is received. Just listening for a certain signal.

I tried googling but to no avail.

Any suggestions? Thanks in advance!!

gEdringer
  • 16,284
  • 3
  • 14
  • 27
  • 1
    As @xbug shows, while waiting on signal is safe and predicable, it's not the original way of handling signal. Program could register few signal handlers during startup, and the OS will stop your program and jump directly into the corresponding handler whenever signal arrives, no matter what state your program is running! It could be bit hard for you to clean up and exit gracefully in the signal handler. – huocp Dec 02 '14 at 23:42
  • What about [`pause()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html)-- suspend the thread until a signal is received? It avoids busy waiting, and it doesn't return until it is interrupted (by some signal; you'd ensure that SIGINT got through to your thread)? This is not the solution if you want the thread to do some other work while waiting for a signal to arrive, but if the thread will be doing nothing until the signal arrives, this is the best way to wait for the signal to arrive. – Jonathan Leffler Dec 03 '14 at 00:02
  • @JonathanLeffler but the thing is, the thread has to keep generating data and store them into a heap, so waiting is not an option. :P – gEdringer Dec 03 '14 at 12:39
  • Then `pause()` is not the answer to your problem. – Jonathan Leffler Dec 03 '14 at 14:45

2 Answers2

4

What about just using a simple signal handler ?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

static void sigint_handler( int signum );
volatile static int done = 0;

int main( int argc, char *argv[] )
{
   if( signal( SIGINT, sigint_handler ) == SIG_ERR ) {
      perror( "signal()" );
      exit(1);
   }

   while( !done ) {
      (void)printf( "working...\n" );
      (void)sleep( 1 );
   }

   (void)printf( "got SIGINT\n" );

   return 0;
}

void sigint_handler( int signum )
{ done = 1; }

EDIT: made done volatile, thanks to Joseph Quinsey for pointing this out in the comments. See this question for a related discussion, also this article.

Community
  • 1
  • 1
xbug
  • 1,394
  • 1
  • 11
  • 18
  • 4
    register signal handler could fail. need to check the return value `signal(SIGINT, sigint_handler)` against `SIG_ERR` – huocp Dec 02 '14 at 23:45
  • Awesome!! Thank you very much!!! This is brilliant :D But isn't defining global variables unsafe? If someone could tweak that variable the code would close as the while loop exits. Is there a safer way of implementing this approach? – gEdringer Dec 03 '14 at 11:44
  • I'm not sure what you mean by "unsafe"; that variable was declared as `static`, so it's not visible to anything outside that file (see case #2 in [this answer](http://stackoverflow.com/a/572550/4256882)). That "someone" would have to be inside the process address space, and know the runtime address of a variable that isn't even exported by the linker, so it's pretty safe (short of being _elegant_). – xbug Dec 03 '14 at 14:15
2

You can block the signal and then use sigtimedwait() with a zero timeout to poll for it.

In the main thread, before creating any other threads, block SIGINT. Subsequently created threads will inherit the signal mask, so SIGINT will be blocked in all threads:

sigset_t sigint_set;

sigemptyset(&sigint_set);
sigaddset(&sigint_set, SIGINT);    
sigprocmask(SIG_BLOCK, &sigint_set, NULL);

Then in the thread that you want to loop around polling for SIGINT:

sigset_t sigint_set;
siginfo_t info;
const struct timespec zero_timeout = { 0, 0 };

sigemptyset(&sigint_set);
sigaddset(&sigint_set, SIGINT);    

while (sigtimedwait(&sigint_set, &info, &zero_timeout) != SIGINT)
{
    /* Do something */
}
caf
  • 233,326
  • 40
  • 323
  • 462