用C中的pthread保持线程数不变

时间:2011-03-01 04:56:33

标签: linux multithreading synchronization pthreads mutex

我试图找到一个解决方案,以便使用pthreads在C语言中保持linux下的工作线程数量不变,但我似乎无法完全理解以下代码的错误:

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

#define MAX_JOBS 50
#define MAX_THREADS 5

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int jobs = MAX_JOBS;
int worker = 0;
int counter = 0;

void *functionC() {
  pthread_mutex_lock(&mutex1);
  worker++;
  counter++;
  printf("Counter value: %d\n",counter);
  pthread_mutex_unlock(&mutex1);

  // Do something...
  sleep(4);

  pthread_mutex_lock(&mutex1);
  jobs--;
  worker--;
  printf(" >>> Job done: %d\n",jobs);
  pthread_mutex_unlock(&mutex1);
}

int main(int argc, char *argv[]) {
  int i=0, j=0;
  pthread_t thread[MAX_JOBS];

  // Create threads if the number of working threads doesn't exceed MAX_THREADS
  while (1) {
    if (worker > MAX_THREADS) {
      printf(" +++ In queue: %d\n", worker);
      sleep(1);
    } else {
      //printf(" +++ Creating new thread: %d\n", worker);
      pthread_create(&thread[i], NULL, &functionC, NULL);
      //printf("%d",worker);
      i++;
    }
    if (i == MAX_JOBS) break;
  }

  // Wait all threads to finish
  for (j=0;j<MAX_JOBS;j++) {
    pthread_join(thread[j], NULL);
  }

  return(0);
}

如果工作线程数低于某个阈值,while(1)循环将继续创建线程。每当工作线程的全局计数器递增(线程创建)和递减(作业完成)时,互斥锁应该锁定关键部分。我认为它可以正常工作,但大多数情况下都可以,但奇怪的事情发生了......

例如,如果我评论(因为它在这个片段中)printf // printf(“+++创建新线程:%d \ n”,worker); while(1)似乎生成一个随机数(在我的经验中为18-25)线程(functionC打印出“计数器值:从1到18-25”......),而不是尊重内部的IF条件环。如果我包含printf,循环似乎以“正确的方式”表现出来......这似乎暗示我应该在main()中添加到循环中以缺少“互斥”条件,以便在MAX_THREADS时有效地锁定线程已达到,但在过去几天更改 LOT 次代码后,我现在有点迷失了。我错过了什么?

请让我知道我应该改变什么才能保持线程数量不变似乎我离解决方案太远...希望......: - )

提前致谢!

1 个答案:

答案 0 :(得分:4)

你的问题是worker在新线程实际启动并运行之前不会递增 - 同时,主线程循环,检查workers,发现它没有改变,并开始另一个线程。它可以重复多次,创建太多线程。

因此,当您决定创建新线程时,需要在主线程中增加worker

你还有另外一个问题 - 你应该使用条件变量让主线程休眠,直到它应该启动另一个线程,而不是使用带有sleep(1);的忙等待循环。完整的固定代码如下:

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

#define MAX_JOBS 50
#define MAX_THREADS 5

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
int jobs = MAX_JOBS;
int workers = 0;
int counter = 0;

void *functionC() {
  pthread_mutex_lock(&mutex1);
  counter++;
  printf("Counter value: %d\n",counter);
  pthread_mutex_unlock(&mutex1);

  // Do something...
  sleep(4);

  pthread_mutex_lock(&mutex1);
  jobs--;
  printf(" >>> Job done: %d\n",jobs);

  /* Worker is about to exit, so decrement count and wakeup main thread */
  workers--;
  pthread_cond_signal(&cond1);

  pthread_mutex_unlock(&mutex1);
  return NULL;
}

int main(int argc, char *argv[]) {
  int i=0, j=0;
  pthread_t thread[MAX_JOBS];

  // Create threads if the number of working threads doesn't exceed MAX_THREADS
  while (i < MAX_JOBS) {
    /* Block on condition variable until there are insufficient workers running */
    pthread_mutex_lock(&mutex1);
    while (workers >= MAX_THREADS)
        pthread_cond_wait(&cond1, &mutex1);

    /* Another worker will be running shortly */
    workers++;
    pthread_mutex_unlock(&mutex1);

    pthread_create(&thread[i], NULL, &functionC, NULL);
    i++;
  }

  // Wait all threads to finish
  for (j=0;j<MAX_JOBS;j++) {
    pthread_join(thread[j], NULL);
  }

  return(0);
}

请注意,即使这样可行,但它并不理想 - 最好先预先创建所需的线程数,然后让它们循环,等待工作。这是因为创建和销毁线程会产生很大的开销,并且因为它通常会简化资源管理。您重写的代码版本如下所示:

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

#define MAX_JOBS 50
#define MAX_THREADS 5

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int jobs = MAX_JOBS;
int counter = 0;

void *functionC()
{
  int running_job;

  pthread_mutex_lock(&mutex1);
  counter++;
  printf("Counter value: %d\n",counter);

  while (jobs > 0) {
    running_job = jobs--;
    pthread_mutex_unlock(&mutex1);

    printf(" >>> Job starting: %d\n", running_job);

    // Do something...
    sleep(4);

    printf(" >>> Job done: %d\n", running_job);

    pthread_mutex_lock(&mutex1);
  }
  pthread_mutex_unlock(&mutex1);

  return NULL;
}

int main(int argc, char *argv[]) {
  int i;
  pthread_t thread[MAX_THREADS];

  for (i = 0; i < MAX_THREADS; i++)
    pthread_create(&thread[i], NULL, &functionC, NULL);

  // Wait all threads to finish
  for (i = 0; i < MAX_THREADS; i++)
    pthread_join(thread[i], NULL);

  return 0;
}