【问题标题】:pthread does not exit in Cpthread 不会在 C 中退出
【发布时间】:2017-05-10 23:39:17
【问题描述】:

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

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

问题是当找到一个单词并且正在关闭其他线程时,程序不会终止(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");
}

【问题讨论】:

  • 你从来没有为threads分配内存。
  • @Barbar 很抱歉没有发布代码的全部相关部分。我实际上已经分配了内存。
  • 您正在阅读由互斥锁保护的代码之外的allreadfound
  • 当这个线程找到匹配时,你在哪里停止其他线程?
  • 假设线程在runthreads() 完成启动所有线程之前找到了单词。 notifyfound() 中的循环只会取消已经启动的线程,不会取消之后启动的线程。

标签: c multithreading pthreads


【解决方案1】:

这与取消点有关,尽管由于您没有分享最小示例,因此很难获得具体信息。我的诊断是

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多