C ++ отмена pthread с использованием вторичного потока, застрявшего в вызове функции - PullRequest
1 голос
/ 11 апреля 2020

У меня проблемы с установкой таймаута в одном из моих 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;
    }
    */
}

Используя эту функцию, я смог проверить, что мой подход к потоку времени ожидания работает. Проблема заключается в том, что когда я запускаю алгоритм CNF (используя Minisat под капотом) после запуска find_vertex_cover, нет никакого способа завершить поток. Ожидается, что алгоритм потерпит неудачу в ситуации, которую я реализую, поэтому тайм-аут реализуется.

Я прочитал об использовании pthread_cancel(), и хотя это не лучший способ, это единственный как я могу реализовать тайм-аут.

Любая помощь по этому вопросу будет принята.

1 Ответ

1 голос
/ 11 апреля 2020

Я прочитал об использовании pthread_cancel (), и хотя это не очень хороший способ [..]

Это верно. pthread_cancel следует избегать. Это особенно плохо для использования в C ++, поскольку оно несовместимо с обработкой исключений. Вы должны использовать std::thread, а для завершения потока вы, возможно, можете использовать условную переменную или переменную atomi c, которая завершает "бесконечное l oop", когда установлено.

Кроме этого, отмена через pthread_cancel зависит от двух вещей: 1) состояние отмены 2) тип отмены.

Состояние отмены по умолчанию включено . Но тип отмены по умолчанию - deferred - это означает, что запрос отмены будет доставлен только в следующую точку отмены. Я подозреваю, что есть какие-либо пункты отмены в find_vertex_cover. Таким образом, вы можете установить тип отмены на asynchronous через вызов:

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

из потоков, которые вы хотите отменить немедленно.

Но опять же, я предлагаю не go для pthread_cancel приближения вообще, а вместо этого переписать логи "отмены" c, чтобы они не включали pthread_cancel.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...