Закрыть поток на основе значения переменной из вызывающего потока

Я использую потоки posix в C. У меня есть две темы в моей программе, thread1 и thread2. поток1 начинает поток2.

thread1 поддерживает переменную var1, в зависимости от которой необходимо безопасно завершить работу thread2.

thread2 вызывает много длинных функций (время выполнения которых может достигать 5 секунд). Существует много распределений памяти с использованием malloc в thread2. Как только var1 становится истиной, мне нужно закрыть thread2, но только после освобождения всех выделенных ячеек памяти. Как это можно сделать?

Код выглядит так:

void * func1(void *arg)
{
   pthread_create(&thread2, &attr, func2, NULL);
   while(1)
   {
      // ...
      var1 = func3();
      if(var1 == true)
      {   
          // Cancel thread2
      }
      // ...
   }
}

void * func2(void *arg)
{
    // ...
    func4(); // runs for 2 sec
    char* var2 = malloc(10);
    func5(); // runs for 5 sec
    char* var3 = malloc(20);
    // ...
 cleanup:
    free(var2);
    free(var3);
    return (void*) 0;
}

2 ответа

Решение

Есть несколько способов сделать это. Вот один из них:

С точки зрения thread1 вы можете просто использовать pthread_cancel на thread2, когда придет время. Но вам нужно соответствующим образом реструктурировать thread2, чтобы убедиться, что он имеет точки отмены в безопасных местах. Вам также необходимо изменить структуру хранения ваших данных, чтобы можно было вызывать обратный вызов отмены для thread2:

struct func2_data {
  char *var2;
  char *var3;
};

void func2_cleanup(void *vdata) {
  struct func2_data *data = vdata;
  free(data->var2);
  free(data->var3);
}

void * func2(void *arg)
{
  struct func2_data data = {
    NULL, NULL
  };

  pthread_cleanup_push(func2_cleanup, &data);

  // ....    

  func4();
  data.var2 = malloc(10);
  pthread_testcancel();

  func5();
  data.var3 = malloc(10);
  pthread_testcancel();

  // ....        

  pthread_cleanup_pop(1);
  return NULL;
}

Так что здесь происходит?

  1. Все указатели, которые необходимо освободить, являются связками и инициализируются в NULL. Это позволяет звонить free действовать на них как на запрет, если функция очистки вызывается до того, как назначена какая-либо одна переменная.

  2. Обратный звонок зарегистрирован, чтобы освободить указатели. Этот обратный вызов будет вызван в любой точке отмены. В том числе, когда поток возвращается из своей функции-обработчика. Так что вам не нужно заботиться об этом прямо там, кроме вызова поп.

  3. Точки отмены добавляются с pthread_testcancelв разных "безопасных" местах. Таким образом, поток может преждевременно заканчиваться между вычислениями. Добавьте их, как считаете нужным.

Несмотря на то, что ваш вопрос не совсем понятен, в приведенном ниже коде я даю идею для решения этих проблем. использование ptread_join для безопасного выхода из ниток

void * func1(void *arg)
{
    pthread_create(&thread2, &attr, func2, (void*)&var1); /* Pass addr of var1 as argument to thread*/
    while(1)
    {
        ...
        var1 = func3();
        if(var1 == TRUE){
            int *ret;
            pthread_join(thread2,&ret);
        }
        ...
    }
}

void * func2(void *arg)
{
    bool *check = (bool*)arg;
    ...
    func4(); // runs for 2 sec
    if(*check == TRUE)
        goto end;
    char* var2 = malloc(10);
    func5(); // runs for 5 sec
    if(*check == TRUE)
        goto clean_var2;
    char* var3 = malloc(20);
    ...
    cleanup:
    free(var3);
    clean_var2:
    free(var2);
    end:
    return (void*) 0;
}
Другие вопросы по тегам