【问题标题】:C++ cancelling a pthread using a secondary thread stuck in function callC ++使用卡在函数调用中的辅助线程取消pthread
【发布时间】:2020-07-23 23:52:24
【问题描述】:

我无法在我的pthreads 之一中设置超时。我在这里简化了我的代码,并将问题隔离为我在线程中运行的 CNF 算法。

int main(){
  pthread_t t1;
  pthread_t t2;
  pthread_t t3; //Running multiple threads, the others work fine and do not require a timeout.

  pthread_create(&t1, nullptr, thread1, &args);
  pthread_join(t1, nullptr);

  std::cout << "Thread should exit and print this\n"; //This line never prints since from what I've figured to be a lack of cancellation points in the actual function running in the thread.

  return  0;
}

void* to(void* args) {
    int timeout{120};
    int count{0};
    while(count < timeout){
        sleep(1);
        count++;
    }
    std::cout << "Killing main thread" << std::endl;
    pthread_cancel(*(pthread_t *)args);
}

void *thread1 (void *arguments){
  //Create the timeout thread within the CNF thread to wait 2 minutes and then exit this whole thread
  pthread_t time;
  pthread_t cnf = pthread_self();
  pthread_create(&time, nullptr, &timeout, &cnf);

  //This part runs and prints that the thread has started
  std::cout << "CNF running\n"; 
  auto *args = (struct thread_args *) arguments;

  int start = args->vertices;
  int end = 1;

  while (start >= end) {
     //This is where the issue lies 
     cover = find_vertex_cover(args->vertices, start, args->edges_a, args->edges_b); 

    start--;
  }

  pthread_cancel(time); //If the algorithm executes in the required time then the timeout is not needed and that thread is cancelled. 
  std::cout << "CNF END\n";
  return nullptr;
}

我尝试注释掉find_vertex_cover 函数并添加一个infinite loop,我能够创建一个timeout 并以这种方式结束线程。该功能实际上以它应该的方式工作。在我运行它的条件下应该永远运行它,因此我需要超时。

//This was a test thread function that I used to validate that implementing the timeout using `pthread_cancel()` this way works. The thread will exit once the timeout is reached.

void *thread1 (void *args) {
    pthread_t x1;
    pthread_t x2 = pthread_self();
    pthread_create(&x1, nullptr, to, &x2);

    /*
    for (int i = 0;i<100; i++){
        sleep(1);
        std::cout << i << std::endl;
    }
    */
}

使用这个函数,我能够验证我的超时线程方法是否有效。问题是当我在运行find_vertex_cover 后实际运行 CNF 算法(在后台使用 Minisat)时,无法结束线程。在我正在实施的情况下,该算法预计会失败,这就是实施超时的原因。

我已经阅读了有关使用 pthread_cancel() 的信息,虽然这不是一个好方法,但它是我可以实现超时的唯一方法。

对于这个问题的任何帮助将不胜感激。

【问题讨论】:

  • 您的格式非常混乱,请修复它。此外,检查您应用的标签以及它们的描述是否真正适合。另外,请确保在您的问题中包含minimal reproducible example。作为新用户,也可以使用tour 并阅读How to Ask
  • 你的代码中定义的函数timeout在哪里?还是它被误命名为to?另请注意,线程的“可取消性”取决于其cancel state and type

标签: c++ linux multithreading concurrency pthreads


【解决方案1】:

我已经阅读了关于使用 pthread_cancel() 的内容,虽然它不是一个好方法 [..]

没错。 pthread_cancel 应该避免。 尤其不适合在 C++ 中使用,因为它与异常处理不兼容。您应该使用std::thread 并且对于线程终止,您可以使用条件变量或在设置时终止“无限循环”的原子变量。

除此之外,通过pthread_cancel 取消取决于两件事:1) 取消状态 2) 取消类型。

默认取消状态是启用。但默认取消类型是 deferred - 这意味着取消请求将仅在下一个取消点交付。我怀疑find_vertex_cover 中有任何取消点。所以你可以通过调用将取消类型设置为asynchronous

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

来自您希望能够立即取消的线程。

但我还是建议完全不要使用pthread_cancel 方法,而是重写“取消”逻辑,使其不涉及pthread_cancel

【讨论】:

  • 设置 state 启用取消。但是 when 它发生是通过 type 控制的(默认情况下是“延迟”)。这就是为什么您需要同时设置两者。顺便说一句,取消状态默认是PTHREAD_CANCEL_ENABLE(所以你不需要设置这个)。
猜你喜欢
  • 2022-01-05
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
  • 2011-05-22
  • 2016-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多