c - C 中 pthread 不退出

标签 c multithreading pthreads

我正在编写一个多线程应用程序,该应用程序读取文件并在线程内存中的文件 block 中查找单词。

如果一个线程首先找到该单词,则需要异步关闭其他寻找该单词的线程。

问题是当找到一个单词并且其他线程正在关闭时,程序不会终止(在 10 次执行中有 6 次)。我在 gdb 中检查过,有一个线程没有退出。即使我不调用 waitforthreads(n_threads),也会发生这种情况。

// [...]
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads;
int allread;
// [...]

int main(int argc, char* argv[]) {
  // [...]
  threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
  pthread_mutex_init(&mutex, NULL);

  runthreads(f, word, n_threads, n_records);
  waitforthreads(n_threads);

  pthread_mutex_destroy(&mutex);
  // [...]
}


void runthreads(FILE* f, char* w, int n_threads, int n_records) {
  struct targs_t args = {w, n_records};
  for (int i=0; i<n_threads; i++)
    pthread_create(&threads[i], NULL, findword, (void*) &args);
}


void waitforthreads(int N) {
  for (int i=0; i<N; i++)
    if(pthread_join(threads[i], NULL))
      exit_(6);
}


void* findword(void* arg) {
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

  struct targs_t* args = (struct targs_t*) arg;
  int max_length = args->n_records * sizeof(record_t);
  record_t* records = malloc(max_length);

  int found = 0;
  while (!allread && !found) {
    pthread_mutex_lock(&mutex);
    // allread is being set in the function below 
    // if the whole file has been read
    readRecords((char*) records, args->n_records, f);
    pthread_mutex_unlock(&mutex);

    for (int i=0; i<args->n_records; i++)
      if (strlen(records[i].text) == 0) break;
      else if (strstr(records[i].text, args->word) != NULL) {
        notifyfound(pthread_self(), records[i].id);
        found = 1;
        break;
      }
  }
  free(records);
  return NULL;
}


void notifyfound(pthread_t tid, int id) {
  printf("Found: %d (%ld)\n", id, (long) tid);
  for (int i=0; i<n_threads; i++)
    if (threads[i] && !pthread_equal(threads[i], tid)) {
      printf(" closing %ld\n", (long) threads[i]);
      pthread_cancel(threads[i]);
    }
  printf(" finished closing\n");
}

最佳答案

这与取消点有关,尽管由于您没有分享最小的示例,所以很难了解具体细节。我的诊断是:

  1. 6/10 次,至少有一个线程在等待互斥体,而另一个线程在 readRecords 中,这将取消并且不会释放互斥体。使用 pthread_cleanup_pushpthread_cleanup_pop 设置取消处理程序,这将释放您的互斥锁,并阅读 pthread_cancel 的手册。 。查看相关pthread_cleanup_push causes Syntax error供一些引用。

  2. 您的某些线程未检测到取消 - 尝试使用 pthread_testcancel 设置有保证的取消点。

下面是一些代码,通过添加取消检查和互斥体清理来修复此类问题。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads = 3;
int allread;
long int count = 0;
int *thread_ids;
int global_quit = 0;
#define MAX 99999

void waitforthreads(int N) {
  printf("waiting for %d threads\n", N);
  for (int i=0; i<N; i++)
    {
      printf("thread %d | %d\n", i, threads[i]);
      if(pthread_join(threads[i], NULL))
        {
          printf("problem\n");
          exit(6);
        }
    }
  printf("done.\n");
}

void notifyfound(pthread_t tid, int count) {
  printf("%d | %d got big number\n", count, pthread_self());
  for (int i=0; i<n_threads; i++)
    if (threads[i] && !pthread_equal(threads[i], tid)) {
      printf(" closing '%ld'\n", (long) threads[i]);
      pthread_cancel(threads[i]);
    }
  global_quit = 1;
  printf(" finished closing\n");
}

void waiting_thread_cleanup(void *arg)
{
  pthread_mutex_unlock((pthread_mutex_t *)arg);
}

void* do_thing(void* arg) {
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

  int* id = (int *)arg;
  int quit = 0;
  while (!allread) {
    pthread_mutex_lock(&mutex);
    pthread_cleanup_push(waiting_thread_cleanup, (void *)&mutex); /* must be paired with pop. */
    if(count++==MAX)
      {
        notifyfound(pthread_self(), *id);
        quit=1;
      }
    else if(count % 10000 == 0)
      printf("[%d] - %d\n", *id, count);
    pthread_testcancel();       /* required to allow for the cancel to ever be 'detected' other functions are sufficient as well. */
    pthread_mutex_unlock(&mutex);
    pthread_cleanup_pop(1);     /* if this isn't here, this will occassionally hand because the mutex isn't freed. */
    if(quit==1)
      {
        printf("%d | %d quitting\n", *id, pthread_self());
        break;
      }
  }
  return NULL;
}

void runthreads(FILE* f, int n_threads) {
  for (int i=0; i<n_threads; i++)
    pthread_create(&threads[i], NULL, do_thing, &(thread_ids[i]));
}

int main(int argc, char* argv[]) {
  threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
  thread_ids = (int*) calloc(n_threads, sizeof(int));
  for(int i=0;i<n_threads;i++)
    thread_ids[i] = i;

  pthread_mutex_init(&mutex, NULL);

  runthreads(f, n_threads);
  waitforthreads(n_threads);

  pthread_mutex_destroy(&mutex);
}

关于c - C 中 pthread 不退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43904260/

相关文章:

c++ - Mac Unix 可执行文件上的段错误,文件编译正常

python - 派生类在 PySide (Qt/PyQt) 的错误线程中接收信号

c - 达到计数 32751 后无法创建线程

c - C程序中单独线程的优点

c++ - 使用 pthread 计算平均运行时间,结果很奇怪

c - 在 Linux 中获取自 1984 年 1 月 1 日午夜以来的绝对时间

c++ - 用于提高中间浮点计算精度的编译器标志

c++ - WSAPoll 更改 FDSET 中的数据并由于 WSAENOTSOCK 返回错误。我正确使用 WSAPoll() 吗?

c - 线程C段错误一个简单的程序

c++ - SSL_CTX_new仅在具有分发版本的32位iOS设备中崩溃