2010-03-03 2 views
1

J'ai 2 threads et file d'attente globale, un thread (t1) push les données et un autre (t2) pop les données, je voulais synchroniser cette opération sans utiliser où nous pouvons utiliser cette file avec section critique utilisant windows API.Comment verrouiller l'adresse de variable de file d'attente au lieu d'utiliser la section critique?

La file d'attente est globale, et je voulais savoir comment synchroniser, est-ce fait en verrouillant l'adresse de file d'attente ?.

Les réponses seront très appréciées. :)

Est-il possible d'utiliser Boost Library pour le problème ci-dessus?

Merci

+0

Une raison spécifique pour laquelle vous ne voulez pas crit section? C'est le plus rapide. – vpram86

+0

Je veux verrouiller l'adresse afin qu'un autre thread puisse attendre avant de claquer. Un problème est survenu en utilisant la section critique, donc décidé de verrouiller la variable lui-même. :) – mahesh

+0

Peut-être qu'il serait préférable de demander comment réparer votre file d'attente qui a utilisé une section critique.Les files d'attente sans verrouillage sont certainement possibles, mais un code sans verrouillage correct est * beaucoup * plus difficile à écrire que le code correct à l'aide de verrous. –

Répondre

3

Une approche est d'avoir deux files d'attente au lieu d'un:

  • le fil de producteur pousse les articles à la file d'attente A.
  • Lorsque le thread consommateur veut apparaître des éléments, la file d'attente A est permuté avec file d'attente vide B.
  • Le thread de production continue de pousser les éléments vers la nouvelle file d'attente A.
  • Le consommateur, sans interruption, consomme des éléments hors de la file d'attente B et les vide.
  • Queue A est permuté avec file d'attente B etc.

Le seul verrouillage/blocage/synchronisation se produit lorsque les files d'attente sont permutés, qui devrait être une opération rapide car il est vraiment une question d'échanger deux pointeurs.

0

Je pensais que vous pourriez faire une file d'attente avec ces conditions sans utiliser Atomics ou tout fil des choses du tout en sécurité?

comme si c'est juste un tampon de cercle, un thread contrôle le pointeur de lecture, et l'autre contrôle le pointeur d'écriture. les deux ne se mettent pas à jour tant qu'ils n'ont pas fini de lire ou d'écrire. et ça marche?

le seul point de difficulté est de déterminer quand lire == écrire si la file d'attente est pleine ou vide, mais vous pouvez surmonter ce problème en avoir juste un élément factice toujours dans la file d'attente

class Queue 
{ 
    volatile Object* buffer; 
    int size; 
    volatile int readpoint; 
    volatile int writepoint; 

    void Init(int s) 
    { 
      size = s; 
      buffer = new Object[s]; 
      readpoint = 0; 
      writepoint = 1; 
    } 

    //thread A will call this 
    bool Push(Object p) 
    { 
     if(writepoint == readpoint) 
     return false; 
     int wp = writepoint - 1; 
     if(wp<0) 
      wp+=size; 
     buffer[wp] = p; 
     int newWritepoint = writepoint + 1; 
     if(newWritepoint==size) 
      newWritePoint = 0; 
     writepoint = newWritepoint; 
     return true; 
     } 

     // thread B will call this 
     bool Pop(Object* p) 
     { 
      writepointTest = writepoint; 
      if(writepointTest<readpoint) 
       writepointTest+=size; 
      if(readpoint+1 == writepoint) 
       return false; 
      *p = buffer[readpoint]; 

     int newReadpoint = readpoint + 1; 
     if(newReadpoint==size) 
      newReadPoint = 0; 
     readpoint = newReadPoint; 
     return true; 
     } 
}; 
+0

Il est possible d'écrire une file d'attente sans verrou - mais ce n'est pas trivial. Voir: http://www.drdobbs.com/cpp/210604448 pour un exemple. –

+0

@Jerry ouais J'ai co-écrit une file d'attente sans verrou, mais ils ont encore un peu «verrouiller» et utiliser des atomiques. ce qui précède devrait fonctionner et être complètement sans verrou et thread sûr si utilisé dans la situation qu'il a spécifié ne devrait-il pas? il n'y a aucune raison de créer une file d'attente sans verrou qui serait plus sûre pour les threads si ce qui précède fonctionne pour ce qu'il veut? Je serais intéressé de savoir si le code ci-dessus == échouer. – matt

+0

Il peut y avoir certaines conditions dans lesquelles cela fonctionnera, mais vous aurez besoin de contraintes explicites (au-delà de ce qu'il a spécifié). Par exemple, il semble exiger que lire et écrire un int soit implicitement atomique. Si Pop() lit à partir de writepoint en même temps que pop lui écrit, et que read/write n'est pas atomique, il peut/aura un sérieux problème. –

0

Une autre façon de gérer ce problème est d'allouer dynamiquement votre file d'attente et de l'assigner à un pointeur. La valeur du pointeur est transmise entre les threads lorsque les éléments doivent être supprimés, et vous protégez cette opération avec une section critique. Cela signifie verrouiller pour chaque poussée dans la file d'attente, mais beaucoup moins de contention sur la suppression des éléments.

Cela fonctionne bien lorsque vous avez beaucoup d'éléments entre la mise en file d'attente et la déqueue, et fonctionne moins bien avec quelques éléments. Exemple (J'utilise une classe de verrouillage RAII donnée pour effectuer le verrouillage). Notez aussi ... vraiment seulement en sécurité quand un seul thread dequeueing.

queue* my_queue = 0; 
queue* pDequeue = 0; 
critical_section section; 

void enqueue(stuff& item) 
{ 
    locker lock(section); 
    if (!my_queue) 
    { 
     my_queue = new queue; 
    } 
    my_queue->add(item); 
} 

item* dequeue() 
{ 
    if (!pDequeue) 
    { //handoff for dequeue work 
     locker lock(section); 
     pDequeue = my_queue; 
     my_queue = 0; 
    } 
    if (pDequeue) 
    { 
     item* pItem = pDequeue->pop(); //remove item and return it. 
     if (!pItem) 
     { 
     delete pDequeue; 
     pDequeue = 0; 
     } 
     return pItem; 
    } 
    return 0; 
} 
Questions connexes