|
FOROS PROFESIONALES WINDEV, WEBDEV y WINDEV Mobile |
| | | | | |
| Multiple reader/single writer implantation |
| Iniciado por Youri JUTEAU, 05,dic. 2018 11:04 - 2 respuestas |
| |
| | | |
|
| |
Miembro registrado 36 mensajes |
|
| Publicado el 05,diciembre 2018 - 11:04 |
Bonjour, Si vous avez comme moi à accéder à des zones mémoires, tableau en lecture, écriture par plusieurs threads, vous vous êtes surement cassé la tête avec des section critiques bloquantes et non performante.
J'ai fait une mise en oeuvre avec une classe qui implémente le patron décrit par Wikipédia: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
Je vous soumet donc cette classe qui peut être utiliser de n'importe où en instanciant un objet local soit en lecture ou en écriture.
Tout se passe dans le constructeur, destructeur.
Le gros avantage est qu'il peut y avoir autant de lecteurs que l'on veut mais un et un seul écrivain. Et lorsque l'écrivain prends la main, on est assuré que les lecteurs sont sortis et qu'ils vont attendre la fin de l'écriture.
ETypeAccèsMémoire est un Enumération AccèsLecture=1 AccèsÉcriture=2 FIN clAccèsMémoire est une Classe CONSTANTE PREFIXE_MUTEX_="MUTEX_ZONEMEMOIRE_" PREFIXE_SIGNAL_="SIGNAL_ZONEMEMOIRE_" FIN PRIVÉ m_sZoneMémoire est une chaîne m_eType est un ETypeAccèsMémoire GLOBAL mg_taLecteur est un tableau associatif d'entiers mg_taMutex est un tableau associatif de chaîne mg_taÉcriture est un tableau associatif de booléen FIN
Procedure Constructeur(sZoneMémoire est une chaîne, eType est un ETypeAccèsMémoire) m_sZoneMémoire=ChaîneFormate(sZoneMémoire,ccSansAccent+ccSansEspace+ccMajuscule) m_eType=eType SI mg_taLecteur[m_sZoneMémoire]..Vide ALORS GénérerAccès(m_sZoneMémoire) FIN SELON m_eType CAS AccèsLecture MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) TANTQUE mg_taÉcriture[m_sZoneMémoire] MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) SignalAttend(PREFIXE_SIGNAL_+m_sZoneMémoire) MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) FIN mg_taLecteur[m_sZoneMémoire]++ SI EnModeTest() ALORS TraceConstruit("Lecture %1 compteur: %2",PREFIXE_MUTEX_+m_sZoneMémoire,mg_taLecteur[m_sZoneMémoire]) FIN MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) CAS AccèsÉcriture MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) TANTQUE mg_taÉcriture[m_sZoneMémoire] MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) SignalAttend(PREFIXE_SIGNAL_+m_sZoneMémoire) MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) FIN mg_taÉcriture[m_sZoneMémoire]=Vrai TANTQUE mg_taLecteur[m_sZoneMémoire]>0 MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) SignalAttend(PREFIXE_SIGNAL_+m_sZoneMémoire) MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) FIN SI EnModeTest() ALORS TraceConstruit("Écriture %1",PREFIXE_MUTEX_+m_sZoneMémoire) FIN MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) FIN Procedure Destructeur() SI m_sZoneMémoire<>"" ALORS SELON m_eType CAS AccèsLecture MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) mg_taLecteur[m_sZoneMémoire] SI mg_taLecteur[m_sZoneMémoire]=0 ALORS SignalOuvre(PREFIXE_SIGNAL_+m_sZoneMémoire) FIN SI EnModeTest() ALORS TraceConstruit("Fin lecture %1 compteur: %2",PREFIXE_MUTEX_+m_sZoneMémoire,mg_taLecteur[m_sZoneMémoire]) FIN MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) CAS AccèsÉcriture MutexDébut(PREFIXE_MUTEX_+m_sZoneMémoire) mg_taÉcriture[m_sZoneMémoire]=Faux SignalOuvre(PREFIXE_SIGNAL_+m_sZoneMémoire) SI EnModeTest() ALORS TraceConstruit("Fin écriture %1",PREFIXE_MUTEX_+m_sZoneMémoire) FIN MutexFin(PREFIXE_MUTEX_+m_sZoneMémoire) FIN FIN
Vous n'avez donc qu'a instancier un objet de lecture avec eType=AccèsLecture et avec eType=AccèsÉcriture pour l'écriture juste avant les portions de codes correspondantes. Vous devez bien sur utiliser la même chaîne sZoneMémoire dans le constructeur pour contrôler le même élément mémoire.
-- Youri JUTEAU Montréal |
| |
| |
| | | |
|
| | |
| |
Miembro registrado 44 mensajes |
|
| Publicado el 07,diciembre 2018 - 13:46 |
Bonjour,
Merci pour le partage, cela est intéressant. Cependant, il manque la fonction GénérerAccès() ca devrait être ?mg_taLecteur[m_sZoneMémoire] = 0 |
| |
| |
| | | |
|
| | |
| |
Miembro registrado 36 mensajes |
|
| Publicado el 07,diciembre 2018 - 15:07 |
Oui possible. Je vais l'ajouter pour voir. Mais je fonctione avec 12 threads qui se partage des dizaines d'endroits tant en lecture qu'en écriture et ça fonctionne comme un charme.
Par contre, le mieux est de déclarer dans le code globale du projet les zones mémoires que l,on prévoit utiliser en multi-threads
clAccèsMémoire.GénérerAccès("gMonTableau"))
Car il semble que la fonction mg_taLecteur[m_sZoneMémoire]..Vide n'est pas thread safe. Ell est appelé dans le constructeur mais si il n'y a pas d'ajout (fait dans l'init du projet), ça ne cause pas de pb.
Ensuite on peut juste créer un objet avant les zone affectées, le constructeur/destructeur fait le reste
Ex:
clMonAccès est un clAccèsMémoire("gMonTableau", ETypeAccèsMémoire.AccèsLecture)
Pour être certain que le destructeur s'éxécute dès que la lecture est terminée.
SI Vrai ALORS clMonAccès est un clAccèsMémoire("gMonTableau", ETypeAccèsMémoire.AccèsLecture) FIN
-- Youri JUTEAU Montréal |
| |
| |
| | | |
|
| | | | |
| | |
| | |
| |
|
|
|