title: How do I interrupt a background thread that's blocking on IO?
body: <p>I have a C program with two threads: the main thread continously reads data from the network and prints it out to the screen, while the secondary thread listens for and handles keypresses from standard input.</p>
  
  <p>Currently my program catches SIGINT, SIGTERM, and SIGPIPE in order to terminate the program cleanly. My problem is that at the end of the main thread (once the main loop has terminated from the signal handler), it attempts to revert the terminal settings using <code>tcsetattr</code>, however this blocks until the current <code>fgetc</code> call on the other thread returns.</p>
  
  <p>How can I interrupt the background thread so that the <code>fgetc</code> call returns and the main thread can restore the terminal settings and exit cleanly?</p>
  
  <p>I have tried using <code>pthread_kill(thread, SIGINT)</code> but that just causes my existing signal handler to be called again.</p>
  
  <p>Relevant code:</p>
  
  <pre><code>// If the program should still be running.
  static sig_atomic_t running = 1;
  
  // Background thread that reads keypresses.
  pthread_t thread;
  
  static void *get_keypresses();
  
  static void receive_signal(int signal) {
      (void)signal;
      running = 0;
  }
  
  int main(int argc, char *argv[]) {
      // Set up signal handling.
      if(signal(SIGINT, receive_signal) == SIG_ERR) {
          fprintf(stderr, "Error setting signal handler for SIGINT.\n");
      }
      if(signal(SIGTERM, receive_signal) == SIG_ERR) {
          fprintf(stderr, "Error setting signal handler for SIGTERM.\n");
      }
      if(signal(SIGPIPE, receive_signal) == SIG_ERR) {
          fprintf(stderr, "Error setting signal handler for SIGPIPE.\n");
      }
  
      // Set up thread attributes.
      pthread_attr_t thread_attrs;
      if(pthread_attr_init(&amp;thread_attrs) != 0) {
          perror("Unable to create thread attributes");
          exit(2);
      }
      if(pthread_attr_setdetachstate(&amp;thread_attrs, PTHREAD_CREATE_DETACHED) != 0) {
          perror("Unable to set thread attributes");
          exit(2);
      }
  
      // Set up terminal for reading keypresses.
      struct termios orig_term_attr;
      struct termios new_term_attr;
      tcgetattr(fileno(stdin), &amp;orig_term_attr);
      memcpy(&amp;new_term_attr, &amp;orig_term_attr, sizeof(struct termios));
      new_term_attr.c_lflag &amp;= ~(ECHO|ICANON);
      tcsetattr(fileno(stdin), TCSANOW, &amp;new_term_attr);
  
      // Start background thread to read keypresses.
      if((pthread_create(&amp;thread, &amp;thread_attrs, &amp;get_keypresses, NULL)) != 0) {
          perror("Unable to create thread");
          exit(2);
      }
  
      // Main loop.
      while(running) {
          // Read data from network and output to screen.
      }
  
      // Restore original terminal attributes. ***IT BLOCKS HERE***
      tcsetattr(fileno(stdin), TCSANOW, &amp;orig_term_attr);
  
      return 0;
  }
  
  // Get input from the keyboard.
  static void *get_keypresses() {
      int c;
      while(running) {
          // Get keypress. ***NEEDS TO BE INTERRUPTED HERE***
          if((c = fgetc(stdin)) != - 1) {
              // Handle keypress.
          }
      }
      return NULL;
  }
  </code></pre>