7

How can I exit or stop a thread immediately?

How can I make it stop immediately when the user enters an answer? I want it to reset for every question.

Here's my code where threading is involved

int q1() {
    int timer_start;
    char ans[] = "lol";
    char user_ans[50];
    timer_start = pthread_create( &xtimer,NULL,(void*)timer_func,(void*)NULL);
    printf("What is the capital city of Peru?\n");

    while(limit){
        scanf("%s",user_ans);
        if(limit)
        {
             if(!strcmp(user_ans, ans))
              {

               // printf("YAY!\n");
                score++;
               // q2();

            }
            else
            {
                game_over();
            }
        }
    }
}
Dariusz
  • 21,561
  • 9
  • 74
  • 114
xDianneCodex
  • 87
  • 1
  • 1
  • 9

4 Answers4

11

You can simply call pthread_cancel on that thread to exit it. And you can send SIGSTOP/SIGCONT signal via pthread_kill to stop/restart it.


But if all you want is a timer, why must you thread?

Piotr Chojnacki
  • 6,837
  • 5
  • 34
  • 65
Naruil
  • 2,300
  • 11
  • 15
  • @xDianneCodex in this case you should use POSIX timer if you want to trigger something when timeout. If you just what to calculate the duration, `gettimeofday` is enough for it. – Naruil Sep 16 '13 at 11:46
  • @xDianneCodex Not to belabor the point, but the time is running anyway. The system clock accessible via `gettimeofday()` (POSIX standard, but all systems will have something parallel) is as accurate as any other means of timing you could implement. You get the time at point A, you get the time at point B, B - A = the time elapsed for whatever took place in between. – CodeClown42 Sep 16 '13 at 11:48
  • 1
    sending `SIGSTOP`/`SIGCONT` affects the whole process, [at least on linux](http://man7.org/linux/man-pages/man3/pthread_kill.3.html). – yyny Sep 05 '19 at 16:16
9

Based on your code I can give a simple answer:

In this case do not use threads at all.

You do not need them. Store the start time, let the user answer, check the time again after user gives an answer.

{
  time_t startTimeSec = time(NULL);

  // answering

  time_t endTimeSec = time(NULL);
  time_t timeTakenSec = endTime-startTime;
  if (timeTaken > 10) { 
    // do your thing
  }
}

To answer your question:

You should use a mutex-protected or volatile variable to asynchronously communicate between threads. Set that variable from one thread and check it in another. Then reset its value and repeat. A simple snippet:

int stopIssued = 0;
pthread_mutex_t stopMutex;

int getStopIssued(void) {
  int ret = 0;
  pthread_mutex_lock(&stopMutex);
  ret = stopIssued;
  pthread_mutex_unlock(&stopMutex);
  return ret;
}

void setStopIssued(int val) {
  pthread_mutex_lock(&stopMutex);
  stopIssued = val;
  pthread_mutex_unlock(&stopMutex);
}

Using pthread_cancel() is an option, but I would not suggest doing it. You will have to check the threads state after this call returns, since pthread_cancel() does not wait for the actual thread stop. And, which to me is even more important, I consider using it ugly.

Dariusz
  • 21,561
  • 9
  • 74
  • 114
  • @xDianneCodex in this case, they were wrong. In my opinion you should only use threads once you really know what you are doing. And to me it seems you are a beginner. Threads are a really difficult concept. It may seem simple to use them, but trust me, there are many pitfalls. – Dariusz Sep 16 '13 at 11:41
  • 7
    @xDianneCodex : If all you are doing is timing how long it takes the user to answer, Dariusz is certainly right. Using a thread for that will be cumbersome and inefficient. Kind of like using a second car to track how far one car is going by following it, when *both cars have an odometer in them anyway.* You only need to check the odometer in the first car. The second one would be totally superfluous. – CodeClown42 Sep 16 '13 at 11:43
  • Agree with @Dariusz. Unless you have some complex logic in your timer logic, you should use a simple Posix timer here. – Naruil Sep 16 '13 at 11:44
  • it has multiple questions though, the program needs the user to answer the questions in only 6 seconds. – xDianneCodex Sep 16 '13 at 11:50
  • +1 ;) `time()` is probably better than my suggested `gettimeofday` if all you need is a granularity in seconds. – CodeClown42 Sep 16 '13 at 11:50
  • I don't know how to use time – xDianneCodex Sep 16 '13 at 11:52
5

Using methods to stop a thread is a brute way. You should rather politely ask the thread to stop by signalling. Thereby the thread will have an option to tidy after itself e.g. if it has allocated memory, which it will not have any opportunity to do if the thread is cancelled.

The method is relatively simple and comprises no OS signalling:

define a thread state variable or structure outside the thread. Point to it at the pthread_create and dereference the state variable in the thread.

int thread_state = 0; // 0: normal, -1: stop thread, 1: do something

static void *thread_1 (void *arg)
{
   int* pthread_state = arg;
   ... // initialize the thread locals
   while(1)
   {
      switch( *pthread_state )
      {
      case 0: // normal thread loop
         ...
         break;
      case -1:
         ... // tidy or whatever is necessary
         pthread_exit(0); // exit the thread signalling normal return
         break;
      case 1: //
         ... // do something special
         break;
      }
   }
}

pthread_create (&t_1, NULL, thread_1, (void*)&thread_state);

...

thread_state = -1; // signal to the thread to stop

// maybe use pthread_exit(0) to exit main.
// this will leave the threads running until they have finished tidy etc.

It is even possible to communicate with the thread using a structure provided that it is simple 'atomic' variables or a simple handshake mechanism is established. Otherwise it may be necessary to use mutex. Use pthread_join to wait for threads to terminate.

172Pilot
  • 51
  • 1
  • 3
0

@Naruil's suggestion to call pthread_cancel() is pretty much the best solution i found, but it won't work if you didn't do the following things.

According to the man-page of pthread_cancel the pthread_cancelibility depend on two thing

  1. thread_cancel_state.
  2. thread_cancel_type.

thread_cancel_state is PTHREAD_CANCEL_ENABLE by default, so our main concern is about the thread_cancel_type, it's default value is type PTHREAD_CANCEL_DEFFERED but we need PTHREAD_CANCEL_ASYNCHRONOUS to set on that thread, which we wan't to cancel.

Following an example given::

#include <stdio.h>
#include <pthread.h>

void *thread_runner(void* arg)
{   
    //catch the pthread_object as argument
    pthread_t obj = *((pthread_t*)arg);

    //ENABLING THE CANCEL FUNCTIONALITY
    int prevType;
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &prevType);

    int i=0;
    for( ; i < 11 ; i++)//1 - > 10
    {
        if(i == 5)
            pthread_cancel(obj);
        else
            printf("count -- %d", i);
    }
    printf("done");
}

int main(int argc, char *argv[])
{
    pthread_t obj;

    pthread_create(&obj, NULL, thread_runner, (void*)&obj);

    pthread_join(obj, NULL);

    return 0;
}

run it using gcc filename.c -lpthread and output the following:: count -- 0 count -- 1 count -- 2 count -- 3 count -- 4

note that the done is never printed because the thread was canceled when the i became 5 & the running thread was canceled. Special thanks @Naruil for the "pthread_cancel" suggestion.

Ratul Sharker
  • 7,484
  • 4
  • 35
  • 44