Home > Software engineering >  to interrupt a sleeping thread when main thread is to exit
to interrupt a sleeping thread when main thread is to exit

Time:10-12

I have a main thread which create child threads to do various task. There is a child thread which is tasked to report on the status every 100s

My current mechanism of stopping the thread is to observe a global boolean. Somewhat like this

Child thread

void* ReportThread(bool* operation)
{
      while(*operation)
      {
        // do its reporting task
        // ........

        int counter = 0;
        while( counter < 100 && operation )
        {
            // let it sleep for 1 seconds and wake up to check
            sleep(1);
            sleepCounter  = 1;
        }
      }
}

Parent (Main) Thread:

bool operation = false;

int main(){
      pthread_t tid;
      err = pthread_create(&tid), NULL, &ReportThread, &operation);
    
      printf("Please input esc to end operation \n");
      while ((ch = getchar()) != 27);
      
      operation =true;
     
      pthread_join(tid,NULL);
     
      return 0;

   }

The problem:

  1. It seem that using sleep(n). The number of seconds seem very inconsistent. When the program is stopped, this thread takes a while maybe 10 second to actually stop
  2. Is there a way to interrupt a thread to sleep? I heard you could use signal. I am coding in linux
  3. Can I just simply just use a pthread_cancel(tid) instead of pthread_join(tid)?

Regards

CodePudding user response:

This part

    while( counter < 100 || operation )
    {
        // let it sleep for 1 seconds and wake up to check
        sleep(1);
        sleepCounter  = 1;
    }

is wrong.

First I assume that sleepCounter = 1; is really a typo and that it should be:

    while( counter < 100 || operation )
    {
        // let it sleep for 1 seconds and wake up to check
        sleep(1);
        counter  = 1;
    }

Then the problem is that even if operation is set to false by some other thread, the while will not finish until counter reach 100.

The code should be

    while( counter < 100 && operation )
    {
        // let it sleep for 1 seconds and wake up to check
        sleep(1);
        counter  = 1;
    }

Further, in main you never set operation to false. Another typo?

CodePudding user response:

You don't need two while loops. And if you want to set a timer, use time functions for it, because sleep is a cancellation point and it is not guaranteed that sleep actually sleeps that amount of time.

Example:

void* ReportThread(void *args)
{
    time_t start = time(NULL);
    time_t now;

    bool *operation = (bool*) args;

    while (*operation) { //while active

        now = time(NULL); //get current time

        if (now - start >= 100) { //if the threshold is exceeded
            start = now; //reset timer
                         //and probably do other stuff
        }

        sleep(1); //sleep for one second

    }

    return NULL;
}

The example above has a max lag of one second, that means if you set operation to false right at that moment when the thread entered the sleep state, you have to wait until sleep returns, only then it will recognize the modified state. The example also has the advantage, that you can easily modify the threshold value (since it depends on the 'real' time, instead of a counter and a non accurate sleep time).

Btw. the variable operation should be either an atomic boolean or protected by a mutex (since it is accessed from different threads).

To answer the questions of your problem:

  1. should be answered by the example above
  2. since i mentioned it before, sleep is a cancellation point, that means it gets interrupted if the process handles a signal (see man pthreads - section Cancellation points).
  3. see man pthread_cancel - section Notes

On Linux, cancellation is implemented using signals. Under the NPTL threading implementation, the first real-time signal (i.e., signal 32) is used for this purpose. On LinuxThreads, the second real-time signal is used, if real-time signals are available, otherwise SIGUSR2 is used.

You cannot use pthread_cancel over pthread_join! You have to use pthread_join in either case (described in detail in the man page).

CodePudding user response:

I don't know if this will fix all your problems, but it's a bit too much for a comment. One problem, your ReportThread function signature is wrong. It should be:

void* ReportThread(void* args);

And then in that function you need to do something like:

void* ReportThread(void* args)
{
  bool* operation = (bool*)args;

  while(*operation)
  {
     ... 
  }
}

I'm not sure how it's working right now, but your compiler should at least be issuing a warning trying to convert a bool* type to a bool.

Also be aware of race conditions on operation

  • Related