使用 C 中的 pthread 保持线程数恒定

发布于 2024-10-19 16:31:54 字数 1769 浏览 2 评论 0原文

我试图找到一个解决方案,以便使用 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);
}

A while (1) 循环不断创建线程,如果工作线程数低于一定阈值。每次工作线程的全局计数器递增(线程创建)和递减(作业完成)时,互斥体应该锁定关键部分。我认为它可以很好地工作,并且在大多数情况下都可以,但是奇怪的事情发生了......

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

请让我知道我应该更改什么以保持线程数恒定,似乎我距离解决方案并不太远...希望...:-)

提前致谢!

I tried to find a solution in order to keep the number of working threads constant under linux in C using pthreads, but I seem to be unable to fully understand what's wrong with the following code:

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

A while (1) loop keeps creating threads if the number of working threads is under a certain threshold. A mutex is supposed to lock the critical sections every time the global counter of the working threads is incremented (thread creation) and decremented (job is done). I thought it could work fine and for the most part it does, but weird things happen...

For instance, if I comment (as it is in this snippet) the printf //printf(" +++ Creating new thread: %d\n", worker); the while (1) seems to generate a random number (18-25 in my experience) threads (functionC prints out "Counter value: from 1 to 18-25"...) at a time instead of respecting the IF condition inside the loop. If I include the printf the loop seems to behave "almost" in the right way... This seems to hint that there's a missing "mutex" condition that I should add to the loop in main() to effectively lock the thread when MAX_THREADS is reached but after changing a LOT of times this code for the past few days I'm a bit lost, now. What am I missing?

Please, let me know what I should change in order to keep the number of threads constant it doesn't seem that I'm too far from the solution... Hopefully... :-)

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

盛装女皇 2024-10-26 16:31:54

您的问题是,在新线程实际启动并开始运行之前,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;
}

Your problem is that worker is not incremented until the new thread actually starts and gets to run - in the meantime, the main thread loops around, checks workers, finds that it hasn't changed, and starts another thread. It can repeat this many times, creating far too many threads.

So, you need to increment worker in the main thread, when you've decided to create a new thread.

You have another problem - you should be using condition variables to let the main thread sleep until it should start another thread, not using a busy-wait loop with a sleep(1); in it. The complete fixed code would look like:

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

Note that even though this works, it isn't ideal - it's best to create the number of threads you want up-front, and have them loop around, waiting for work. This is because creating and destroying threads has significant overhead, and because it often simplifies resource management. A version of your code rewritten to work like this would look like:

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文