Question

Une autre question de synchronisation ... J'espère que vous ne vous énervez pas;)

Supposons le scénario suivant: une structure de données centrale (très grande, donc je ne veux pas vraiment la rendre immuable et la copier à chaque changement. Je ne veux même pas conserver plusieurs copies en mémoire), plusieurs unités de lecture qui accèdent à cette structure de données en lecture seule et une unité d'écriture qui maintient la structure de données à jour en arrière-plan.

Je synchronise actuellement tous les accès à la structure de données, ce qui fonctionne parfaitement (pas d'effets de synchronisation, pas de blocages). Ce que je n'aime pas dans cette approche, c'est que la plupart du temps, j'ai beaucoup de threads de lecture actifs et que le thread d'écriture n'est actif que de temps en temps. Maintenant, il est complètement inutile que les threads du lecteur attendent la fin des autres threads du lecteur. Ils pourraient facilement accéder à la structure de données en parallèle tant que le fil d'écriture n'est pas en train d'écrire.

Existe-t-il un moyen élégant et élégant de résoudre ce type de scénario?

MODIFIER: Merci beaucoup pour les réponses et les liens! Permettez-moi d'ajouter une autre question brève et connexe: si le code exécuté dans les sections critiques du lecteur ne prend que très peu de temps (comme une simple recherche dans une table de hachage), vaut-il la peine d'envisager de mettre en œuvre l'une des techniques que vous décrivez ou est-ce la sérialisation? effet des serrures pas si mal dans ce cas? L'évolutivité et les performances sont très importantes. Qu'en penses-tu?

EDIT 2: Je viens d'examiner une implémentation d'un seul écrivain / plusieurs lecteurs: un verrou et cette implémentation utilise un moniteur pour synchroniser du code dans la méthode WaitToRead. Cela ne provoque-t-il pas le même effet de sérialisation que je voulais éviter en premier lieu? (Toujours en supposant que le code à synchroniser est court et rapide)

Était-ce utile?

La solution

Il existe une classe à cette fin dans RTL (sysutils): TMultiReadExclusiveWriteSynchroniser

Il est très facile à utiliser. Vous n'avez pas besoin de catégoriser strictement vos discussions comme lecteur ou écrivain. Il suffit d'appeler " BeginRead " ou " BeginWrite " dans un thread pour démarrer une opération thread-safe. Appelez " EndRead " ou " EndWrite " pour terminer l'opération.

Autres conseils

Ce que vous recherchez (et ce que vartec a décrit) est appelé Reader (s) -Writer -Lock .

Vous trouverez des informations détaillées sur la résolution de ce problème à l'adresse msdn magazine et un extrait des applications de programmation pour MS Windows .

L'utilisation d'un verrou Reader-Writer résoudra le problème. Plusieurs lecteurs peuvent accéder à une base de données et un rédacteur est verrouillé une fois que tous les lecteurs ont fini de lire.

Toutefois, cela pourrait empêcher le rédacteur d’avoir jamais accès à la source car de nouveaux lecteurs veulent toujours y accéder. Cela peut être résolu en bloquant les nouveaux lecteurs lorsqu'un rédacteur veut accéder: il a une priorité plus grande. L’écrivain obtient l’accès une fois que tous les lecteurs de la source ont fini de lire.

Chaque fois que le rédacteur souhaite accéder, vous mettez en file d'attente les lecteurs entrants (laissez-les attendre la condition), attendez que les lecteurs actifs se terminent, écrivez et, une fois l'opération terminée, laissez les lecteurs en attente y accéder.

Personne ne peut vraiment répondre à votre question de savoir si la sérialisation affectera beaucoup les performances de votre application. Vous devez définir vous-même ce profil et les résultats dépendront grandement du nombre de threads, de cœurs et de la charge de travail spécifique.

Notez cependant que l'utilisation d'une synchronisation plus intelligente que les sections critiques, telles que le verrou lecteur-écrivain-verrou, peut introduire famine problèmes qui peuvent être difficiles à résoudre et à résoudre. Vous devez vraiment examiner de près si le débit accru l'emporte sur les problèmes potentiels. Notez également qu’il n’ya pas réellement d’augmentation du débit, en particulier si le code verrouillé est très court et rapide. Il existe un bel article de Jeffrey Richter qui contient en réalité cette citation:

  

Performances Même lorsqu'il n'y a pas de conflit pour un ReaderWriterLock, ses performances sont très lentes. Par exemple, un appel à sa méthode AcquireReaderLock prend environ cinq fois plus de temps qu’un appel à la méthode Enter de Monitor.

Ceci est pour .NET bien sûr, mais les principes sous-jacents s'appliquent également.

Le verrou lecteur-écrivain est ce dont vous avez besoin. Le didacticiel contient une description, mais je suis sûr que quelqu'un l'ajoute en tant que norme à Delphi. Cela vaut peut-être la peine d’être vérifié. D2009 ne l’a pas déjà.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top