4 votes

Limiter le nombre de threads simultanés (avec pthreads)

Je dois écrire une application en C qui publie des informations sur le web en utilisant CURL. L'application doit exécuter jusqu'à N (disons 10) requêtes en parallèle au maximum. Comment puis-je attendre que N'IMPORTE QUEL thread se termine, plutôt qu'un thread spécifique qui utilise pthread_join() .

J'ai lu sur pthread_cond_wait, mais la plupart des exemples montrent comment le thread de contrôle (main) réveille un thread de travail. J'ai besoin de l'inverse - les threads de travail doivent pouvoir signaler/réveiller le thread parent avant de se terminer.

Mise à jour : En fait, j'ai besoin d'un moyen pour faire dormir le thread manager et quand un thread worker termine son travail, il doit réveiller le thread manager pour lui donner un autre travail. Cela n'a pas d'importance si le thread se termine et qu'un nouveau thread est créé pour le travail ou si le pool de threads est utilisé. Il faut tout de même qu'il y ait un moyen de signaler au manager qu'un travail est terminé.

J'espère que je ne recevrai pas cette suggestion. :

while(asleep){
  for(i = 0; i< threadCount; i++){
    pthread_mutex_lock(mutex);
    if(threads[i] == IDLE_STATE)
      startNewJob();
    pthread_mutex_unlock(mutex);
    usleep(100*1000);
  }
}

4voto

simonc Points 30279

Plutôt que de créer/détruire des threads à la demande, il sera plus facile de créer un pool de 10 threads de travail au démarrage et de demander à votre programme principal de leur fournir des tâches.

Au démarrage, vous créeriez un tableau de 10 travailleurs. Ceux-ci pourraient ressembler à quelque chose comme

typedef struct worker
{
    pthread_t       thread;
    pthread_cond_t  cond;
    pthread_mutex_t mutex;
    struct job*     job;
    int             quit;
} worker;

Le gestionnaire délègue les tâches à chaque thread à tour de rôle en définissant leur job puis en signalant le travailleur.

Chaque travailleur effectue une boucle jusqu'à ce que quit était non nulle, en attendant que son état soit signalé. Après chaque signal, il lit/traite son job avant de communiquer les résultats et d'attendre à nouveau son état.

Editer : Vous n'aimez pas les pools de discussion. Vous pourriez plutôt essayer de donner à chaque thread un identifiant unique ; stocker une correspondance entre les identifiants et d'autres propriétés de chaque thread dans le gestionnaire. Lorsque chaque thread se termine, il doit ajouter son identifiant à une liste appartenant au gestionnaire, puis signaler une condition dans le gestionnaire. Chaque fois que le gestionnaire se réveille, il peut extraire la tête de la liste, rechercher le fil de discussion approprié, lire les résultats de son travail, puis rejoindre le fil de discussion. Notez que la liste du manager sera accédée par plusieurs threads, donc les lectures/écritures devront être protégées par un mutex.

Edit2 : Vous aimeriez en savoir plus sur les conditions et les exemples que vous avez trouvés ne vous aident pas. Je ne suis pas sûr que ce soit mieux, mais voici ce qui suit un peu de code que j'ai écrit . Les OsSemaphore* permettent d'intégrer des conditions dans une API simple de type Attente/Signal.

1voto

Douglas Leeder Points 29986

Vous voulez une variable de condition, les mêmes fonctions que celles que vous avez examinées, mais inversées. La condition que vous attendez est "un thread de travailleur a terminé son travail".

le fil conducteur le fait :

  • verrouiller le mutex
  • tant qu'aucun thread n'a terminé : pthread_cond_wait
  • débloquer le mutex
  • planifier le travail
  • boucle

Chaque thread de travailleur, lorsqu'il a terminé son travail, le fait :

  • verrouiller le mutex
  • marque complétée
  • pthread_cond_signal
  • débloquer le mutex
  • quitter ou attendre le travail

1voto

caf Points 114951

Les conditions variables sont ce que vous recherchez. Elles peuvent être utilisées tout aussi facilement pour signaler le thread du gestionnaire au thread du travailleur que l'inverse.

Votre exemple de paille à la fin est en fait très similaire à ce que vous pourriez faire en utilisant une variable de condition :

pthread_mutex_lock(&mutex);
while (!finished) {
  for(i = 0; i < threadCount; i++) {
    if(threads[i] == IDLE_STATE)
      startNewJob(i);
  }

  /* Not finished, and no idle threads, so wait */
  if (!finished)
    pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);

Lorsqu'un fil est terminé, il est simplement terminé :

pthread_mutex_lock(&mutex);
threads[self] = IDLE_STATE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X