How do I stop a thread that is blocked on a system call or performing I/O?

Article ID: 813
Last updated: 05 Feb, 2008
Article ID: 813
Last updated: 05 Feb, 2008
Revision: 1
Views: 19133
Posted: 14 Feb, 1998
by Dean J.
Updated: 05 Feb, 2008
by Dean J.
Problem


If one of my threads is blocked during a system call, or is doing some I/O (perhaps talking to another program with a socket), how do I stop the thread?


Cause


Under normal circumstances, one would use the requestCancellation()/serviceCancellation() mechanism to stop a thread, and allow it to properly cleanup its resources. However, if a thread is blocked doing something, it won't be able to perform serviceCancellation()'s, and so won't be able to respond and deal with outside serviceCancellation()>'s.


Action


There are at least three ways of handling this problem that have worked for other customers. They are presented here in order of most to least favorable. Examine them and think about what would be most appropriate in your application; some may work better in some situations than others. You may also be able to find yet another solution which works best for you.

  1. Many blocking calls (such system I/O) can be called asynchronously, which means they won't block. Usually they return some handle to the invocation of the function, which can later be used to check if the function is done. You may be able to switch to an asynchronous version of a call, which will allow you to perform serviceCancellation()'s when done. Here's a hypothetical example:

    First, a blocking call:

      result = someSystemCall(param1, param2);  // This blocks for a long time to get the result.

    Now, a hypothetical non-blocking version of it:

      handleToResult = someSystemCall_nonblocking(param1, param2);  // This returns instantly
      while(!resultIsReady(handleToResult)) { // resultIsReady is a hypothetical system
      // call which tells us if our non-blocking
      // function is done. It also does not block.
      ::rwServiceCancellation(); // Service any cancellation requests
      ::rwSleep(25); // Sleep to avoid using all the CPU
      }

    Again, while the system calls here were hypothetical, the general principle will apply to any call that has a non-blocking equivalent.

  2. Launch a seperate thread to perform the blocking call, and terminate() it if you need to stop the thread. You can use the IOU mechanism of Threads.h++ for this purpose:
      ...
      void myThreadFunction(void)
      {
      // Do some work

      // I need to invoke the blocking function someSystemCall
      // so I'll run it in a different thread.
      // It's declaration is Result someSystemCall(int, int);
      RWThreadIOUFunction someSystemCall_thread = rwMakeThreadIOUFunction(someSystemCall, param1, param2);
      someSystemCall_thread.start();

      // Get the result object from the thread
      RWThreadIOUResult resultIOU = someSystemCall_thread.result();

      // Now, wait for the function to get done, and service cancellation attempts while I wait. If somebody tries to cancel me, Kill the thread calling someSystemCall.
      try {
      while(!resultIOU.redeemable()) {
      ::rwServiceCancellation();
      ::rwSleep(25);
      }
      }
      catch(RWCancellation &c) {
      // OK, someone asked me to cancel, terminate the
      // thread we spawned and proceed with the cancel.
      someSystemCall_thread.terminate();
      // Rethrow the RWCancellation to proceed with the cancel
      throw c;
      }

      // OK, we got a result from the thread, we can use it
      Result r = resultIOU; // r is the Result from calling someSystemCall.

      }

    Similar techniques can be used even if your blocking call has multiple output parameters. Check your Threads.h++ User's Guide and your Threads.h++ Reference Guide to see how to use IOU's to convert a synchronous call into an asynchronous call, as we did here.

  3. You may be able to get away with simply calling terminate() on the thread that is blocked. However, you should only do this in very exceptional circumstances, for example, if you are terminating your whole application. Terminating a thread that has acquired a mutex or some other synchronization object could cause deadlock as other threads may be waiting for the lock to release. Use EXTREME CAUTION when explicitly terminate()'ing threads!

For more detailed information on this topic, refer to your Threads.h++ User's Guide and your Threads.h++ Reference Guide. They contain useful information on how to best handle this situation.

This article was:   Helpful | Not helpful
Report an issue
Article ID: 813
Last updated: 05 Feb, 2008
Revision: 1
Views: 19133
Posted: 14 Feb, 1998 by Dean J.
Updated: 05 Feb, 2008 by Dean J.
Also read


Others in this category