【问题标题】:How to stop a running pthread thread?如何停止正在运行的 pthread 线程?
【发布时间】:2026-02-12 19:30:01
【问题描述】:

如何立即退出或停止线程?

当用户输入答案时,如何让它立即停止? 我希望它为每个问题重置。

这是我的涉及线程的代码

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();
            }
        }
    }
}

【问题讨论】:

    标签: c multithreading pthreads


    【解决方案1】:

    根据你的代码,我可以给出一个简单的答案:

    在这种情况下,根本不要使用线程。

    你不需要它们。存储开始时间,让用户回答,用户回答后再次查看时间。

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

    回答您的问题:

    您应该使用受互斥体保护的变量或 volatile 变量在线程之间进行异步通信。从一个线程设置该变量并在另一个线程中检查它。然后重置其值并重复。一个简单的sn-p:

    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);
    }
    

    使用pthread_cancel() 是一种选择,但我不建议这样做。您必须在此调用返回后检查线程状态,因为pthread_cancel() 不会等待实际的线程停止。而且,对我来说更重要的是,我认为使用它很丑。

    【讨论】:

    • @xDianneCodex 在这种情况下,他们错了。在我看来,只有当你真正知道自己在做什么时,才应该使用线程。对我来说,你似乎是个初学者。线程是一个非常困难的概念。使用它们可能看起来很简单,但相信我,有很多陷阱。
    • @xDianneCodex :如果您所做的只是计算用户回答所需的时间,那么 Dariusz 肯定是对的。为此使用线程将是麻烦且低效的。有点像使用第二辆车来跟踪一辆车的行驶距离,但无论如何,两辆车都有里程表。您只需要检查第一辆车的里程表。第二个完全是多余的。
    • 同意@Dariusz。除非你的定时器逻辑中有一些复杂的逻辑,否则你应该在这里使用一个简单的 Posix 定时器。
    • 虽然有多个问题,但程序需要用户在 6 秒内回答问题。
    • +1 ;) time() 可能比我建议的 gettimeofday 更好,如果您只需要以秒为单位的粒度。
    【解决方案2】:

    您只需在该线程上调用pthread_cancel 即可退出它。您可以通过pthread_kill 发送 SIGSTOP/SIGCONT 信号来停止/重启它。


    但如果你想要的只是一个计时器,那你为什么必须线程呢?

    【讨论】:

    • @xDianneCodex 在这种情况下,如果您想在超时时触发某些东西,您应该使用 POSIX 计时器。如果你只是计算持续时间,gettimeofday 就足够了。
    • @xDianneCodex 不必强调这一点,但无论如何时间都在流逝。通过gettimeofday() 访问的系统时钟(POSIX 标准,但所有系统都会有一些并行)与您可以实现的任何其他计时方式一样准确。你得到 A 点的时间,你得到 B 点的时间,B - A = 两者之间发生的任何事情所经过的时间。
    • 发送SIGSTOP/SIGCONT会影响整个流程,at least on linux
    【解决方案3】:

    使用方法来停止线程是一种粗暴的方式。 你应该礼貌地通过信号来请求线程停止。 因此,线程将可以选择自行整理,例如如果它已经分配了内存,如果线程被取消,它将没有任何机会做。

    该方法相对简单,不包括操作系统信令:

    在线程外定义线程状态变量或结构。在 pthread_create 处指向它并取消引用线程中的状态变量。

    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.
    

    如果它是简单的“原子”变量或建立了简单的握手机制,甚至可以使用结构与线程通信。否则可能需要使用互斥锁。 使用 pthread_join 等待线程终止。

    【讨论】:

      【解决方案4】:

      @Naruil 建议调用 pthread_cancel() 几乎是我找到的最佳解决方案,但如果您不执行以下操作,它将无法正常工作。

      根据man-page of pthread_cancel,pthread_cancelibility 取决于两件事

      1. thread_cancel_state。
      2. thread_cancel_type.

      thread_cancel_state默认是PTHREAD_CANCEL_ENABLE,所以我们主要关心的是thread_cancel_type,它的默认值是PTHREAD_CANCEL_DEFFERED em> 但我们需要 PTHREAD_CANCEL_ASYNCHRONOUS 来设置该线程,我们不想取消它。

      下面给出一个例子::

      #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;
      }
      

      使用 gcc filename.c -lpthread 运行它并输出以下内容: 计数——0 数——1 数——2 数——3 数 -- 4

      请注意,done 永远不会被打印出来,因为当 i 变为 5 时线程被取消并且正在运行的线程被取消。特别感谢@Naruil 的“pthread_cancel”建议。

      【讨论】: