2010-10-30 11 views
2

Quelque chose que je ne comprends pas l'algorithme classique du problème producteur-consommateur (de Wikipedia :)multithreading: algorithme producteur-consommateur classique

semaphore mutex = 1 
semaphore fillCount = 0 
semaphore emptyCount = BUFFER_SIZE 

procedure producer() { 
    while (true) { 
     item = produceItem() 
     down(emptyCount) 
      down(mutex) 
       putItemIntoBuffer(item) 
      up(mutex) 
     up(fillCount) 
    } 
    up(fillCount) //the consumer may not finish before the producer. 
} 

procedure consumer() { 
    while (true) { 
     down(fillCount) 
      down(mutex) 
       item = removeItemFromBuffer() 
      up(mutex) 
     up(emptyCount) 
     consumeItem(item) 
    } 
} 

Je constate que les producteurs et les consommateurs verrouillent « mutex » avant jouer avec le tampon, et le déverrouiller par la suite. Si tel est le cas, c'est-à-dire qu'un seul thread accède au tampon à un moment donné, je ne vois pas vraiment comment l'algo ci-dessus diffère d'une simple solution qui consiste à mettre un mutex de garde sur le tampon:

 
semaphore mutex = 1 

procedure producer() { 
    while (true) { 
     item = produceItem() 
     flag = true 
     while (flag) { 
      down(mutex) 
      if (bufferNotFull()) { 
       putItemIntoBuffer(item) 
       flag = false 
      } 
      up(mutex) 
     } 
    } 
} 


procedure consumer() { 
    while (true) { 
     flag = true 
     while (flag) { 
      down(mutex) 
      if (bufferNotEmpty()) { 
       item = removeItemFromBuffer() 
       flag = false 
      } 
      up(mutex) 
     } 
     consumeItem(item) 
    } 
} 

La seule chose à laquelle je pense qui nécessite l'utilisation des sémaphores 'fillCount' et 'emptyCount' est programmant. Peut-être que le premier algo est pour s'assurer que dans un état où 5 consommateurs attendent sur un tampon vide (zéro 'fillCount'), il est assuré que quand un nouveau producteur arrive, il va passer son "down" (emptyCount) "déclaration rapidement et obtenir le« mutex »rapidement.

(alors que dans l'autre solution, les consommateurs auront inutilement le 'mutex' seulement pour l'abandonner jusqu'à ce que le nouveau producteur l'obtienne et insère un article).

Ai-je raison? Est-ce que je manque quelque chose?

Répondre

3

S'il n'y a pas de messages dans le tampon, le consommateur va descendre le mutex, vérifier le tampon, trouver qu'il est vide, remonter le mutex, rebondir et répéter immédiatement le processus. En termes simples, les consommateurs et les producteurs sont bloqués dans des boucles occupées qui mâchent 100% d'un noyau de CPU. Ce n'est pas seulement un problème théorique. Vous pouvez très bien constater que le ventilateur de votre ordinateur commence à tourner chaque fois que vous exécutez votre programme.

+0

Merci pour votre réponse rapide. Donc, lorsque j'utilise l'algorithme correct, je dois me fier aux opérations up(), down() pour ne pas écraser l'unité centrale ... Je veux dire qu'une prémisse de cet algorithme est que ces opérations ne le font pas magiquement, n'est-ce pas? – bloodcell

+1

Oui, l'algorithme dépend du fait que, si le sémaphore est à zéro, l'opération 'down()' mettra le thread qui l'a appelé à dormir jusqu'à ce que quelqu'un appelle 'up()' sur le même sémaphore. –

0

Il y a un problème affamé si plus d'un consommateur est impliqué. Dans le dernier exemple, le consommateur vérifie un article dans une boucle. Mais au moment où il essaye de réessayer, un autre consommateur peut "voler" son objet. Et la prochaine fois encore, et encore. Ce n'est pas gentil.

+0

L'élément est supprimé du tampon avant que le mutex soit libéré, donc s'il y a un élément, le consommateur actuel l'obtient. Peu importe le consommateur qui l'obtient, dans la plupart des cas, mais que les consommateurs ne voient jamais un tampon vide avec des éléments ou un tampon non vide qui n'a aucun élément. Le mutex est suffisant pour ça. Le deuxième programme fait beaucoup de sondages, cependant. – cHao

1

Il n'y a pas que le verrouillage du tampon qui se passe.

Le sémaphore fillCount dans le premier programme est de mettre en pause le (s) consommateur (s) lorsqu'il ne reste plus rien à consommer. Sans cela, vous êtes constamment en train d'interroger le tampon pour voir s'il y a quelque chose à obtenir, et c'est tout à fait inutile.

De même, le sémaphore emptyCount met le producteur en pause lorsque le tampon est plein.

1

Le concept de trou du modèle producteur/consommateur est que la ressource partagée n'est accessible que si certains critères sont remplis. Et de ne pas utiliser les cycles de processeur inutiles afin de s'assurer qu'ils sont satisfaits.

consommation:

  • Attendez s'il n'y a rien à consommer (=> tampon vide).

Producteur:

  • Attendez s'il n'y a pas assez d'espace dans la mémoire tampon.

Et pour les deux est très important de noter:

  • Wait = Spin attente