I possède une file d'attente dans laquelle je peux en file d'attente différents threads, je peux assurer deux choses:Meilleure approche pour la file d'attente synchronisé de fil
- appel sont traitées une par une.
- demande sont traitées dans l'ordre d'arriver
Deuxième point est important. Sinon, une section critique simple suffirait. J'ai différents groupes de requêtes et seulement dans un seul groupe ces points doivent être remplis. Les demandes provenant de différents groupes peuvent être simultanées.
Il ressemble à ceci:
FTaskQueue.Enqueu('MyGroup');
try
Do Something (running in context of some thread)
finally
FTaskQueue.Dequeu('MyGroup');
end;
EDIT: Je l'ai supprimé la mise en œuvre effective, car il cache le problème que je veux résoudre
J'ai besoin parce que j'ai un serveur web basé Indy qui accepte les requêtes http. D'abord je trouve une session correspondant à la demande. Ensuite, la demande (code) est exécutée pour cette session. Je peux obtenir plusieurs demandes pour la même session (lire Je peux obtenir de nouvelles demandes pendant que la première est en cours de traitement) et elles doivent s'exécuter une par une dans le bon ordre d'arrivée. Je recherche donc une file d'attente de synchronisation générique qui peut être utilisée dans de telles situations afin que les requêtes puissent être mises en file d'attente. Je n'ai aucun contrôle sur les threads et chaque requête peut être exécutée dans un thread différent. Quelle est la meilleure approche (ususal) pour ce genre de problème? Le problème est que Enqueue et Dequeue doivent être des opeations atomiques afin que l'ordre correct soit preserverd. Ma mise en œuvre actuelle a un goulot d'étranglement substantiel, mais cela fonctionne.
EDIT: Bellow est le problème des opérations atomiques Enqueue/DEQUEUE
Vous Wold normaly faire quelque chose comme ceci:
procedure Enqueue;
begin
EnterCriticalSection(FCritSec);
try
DoEnqueue;
finally
LeaveCriticalSection(FCritSec);
end;
BlockTheCurrentThread; // here the thread blocks itself
end;
procedure Dequeue;
begin
EnterCriticalSection(FCritSec);
try
DoDequeue;
UnblockTheNextThread; // here the thread unblocks another thread
finally
LeaveCriticalSection(FCritSec);
end;
end;
Maintenant, le problème ici est que ce n'est pas atomique. Si vous avez déjà un thread dans la file d'attente et qu'un autre vient et appelle Enqueue, il peut arriver que le second thread quitte la section critique et essaie de se bloquer. Maintenant, le planificateur de thread reprendra le premier thread, qui tentera de débloquer le prochain (second) thread. Mais le deuxième thread n'est pas encore bloqué, donc rien ne se passe. Maintenant, le deuxième thread continue et se bloque, mais ce n'est pas correct car il ne sera pas débloqué. Si le blocage est à l'intérieur de la section critique, que la section critique n'est jamais relâchée et que nous avons un blocage.
Si vous avez plusieurs threads qui se suspendent et se reprennent pour s'assurer qu'un seul s'exécute à un moment donné - alors vous devriez vous rendre compte que tout votre design est faux. Dans ce cas, une requête ne doit pas * être * égale à un thread. – mghie
Je soupçonne que l'approche n'est pas correcte oui. Mais disons que j'ai un serveur Indy. Je reçois des requêtes http dans un gestionnaire d'événements de serveur Web. Je trouve une session à travers une table de hachage puis j'exécute la requête = exécuter du code pour cette session. Maintenant, si pour une même session je reçois plusieurs requêtes, elles doivent être exécutées une par une. Et chacun sera dans un contexte de fil différent. Je n'ai aucun contrôle sur les threads. Si vous connaissez une meilleure approche, veuillez l'écrire comme réponse. – Runner
Je vois, mais ces contraintes ne sont pas du tout visibles à partir de votre question. Je pense que vous obtiendriez de bien meilleures réponses si vous supprimez les détails de votre propre solution, énoncez le problème uniquement et demandez des approches pour le résoudre. – mghie