【问题标题】:to interrupt a sleeping thread when main thread is to exit当主线程要退出时中断正在休眠的线程
【发布时间】:2021-10-11 03:55:17
【问题描述】:

我有一个主线程,它创建子线程来执行各种任务。有一个子线程的任务是每 100 秒报告一次状态

我目前停止线程的机制是观察一个全局布尔值。有点像这样

子线程

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

父(主)线程:

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;

   }

问题:

  1. 似乎在使用 sleep(n)。秒数似乎很不一致。当程序停止时,该线程需要一段时间才能真正停止,可能需要 10 秒
  2. 有没有办法中断线程休眠?我听说你可以使用信号。我在 linux 中编码
  3. 我可以直接使用 pthread_cancel(tid) 代替 pthread_join(tid) 吗?

问候

【问题讨论】:

    标签: c linux signals


    【解决方案1】:

    这部分

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

    错了。

    首先我假设sleepCounter += 1; 确实是一个错字,应该是:

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

    那么问题是即使operation被其他线程设置为false,while也不会在counter达到100之前完成。

    代码应该是

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

    此外,在 main 中,您永远不会将 operation 设置为 false。又一个错字?

    【讨论】:

    • 是的,这是一个错字...抱歉在打字时犯了错误
    【解决方案2】:

    您不需要两个 while 循环。如果您想设置一个计时器,请为其使用时间函数,因为sleep 是一个取消点,并且不能保证sleep 实际上会休眠该时间。

    示例:

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

    上面的例子有1秒的最大延迟,这意味着如果你在线程进入睡眠状态的那一刻将operation设置为false,你必须等到sleep返回,然后才返回它将识别修改后的状态。该示例还有一个优点,即您可以轻松修改阈值(因为它取决于“实时”时间,而不是计数器和不准确的睡眠时间)。

    顺便说一句。变量operation 应该是原子布尔值或受互斥体保护(因为它是从不同线程访问的)。

    回答你的问题:

    1. 应该用上面的例子来回答
    2. 因为我之前提到过,sleep 是一个取消点,这意味着如果进程处理一个信号,它就会被中断(参见man pthreads - 取消点部分)。
    3. 参见man pthread_cancel - 注释部分

    在 Linux 上,取消是使用信号实现的。在 NPTL 线程实现下,第一个实时信号(即信号 32)用于此目的。在 LinuxThreads 上,如果实时信号可用,则使用第二个实时信号,否则使用 SIGUSR2。

    您不能使用pthread_cancel 超过pthread_join!无论哪种情况,您都必须使用pthread_join(在手册页中有详细描述)。

    【讨论】:

      【解决方案3】:

      我不知道这是否能解决您的所有问题,但评论有点过分。一个问题,你的ReportThread 函数签名是错误的。应该是:

      void* ReportThread(void* args);
      

      然后在该函数中,您需要执行以下操作:

      void* ReportThread(void* args)
      {
        bool* operation = (bool*)args;
      
        while(*operation)
        {
           ... 
        }
      }
      

      我不确定它现在是如何工作的,但您的编译器至少应该发出警告,尝试将 bool* 类型转换为 bool

      还要注意operation 上的竞争条件

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 2020-05-21
        • 1970-01-01
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-12
        • 1970-01-01
        相关资源
        最近更新 更多