Comment correctement détruire pthread mutex
Exactement comment je peut détruire un pthread mutex variable ?
Voici ce que je veux faire.
Je veux avoir des objets (variables de structure) mis en cache , qui sont considérés par clé.
Je veux avoir un minimum de granularité de serrures ici. Donc je veux avoir un verrou pour chaque
objet probablement incorporé dans la structure, de sorte que je peux avoir au niveau de l'objet de verrouillage.
Maintenant, le problème est de savoir comment détruire en toute sécurité de ces objets ?
Regarde comme la première étape consiste à retirer l'objet à partir de la table de recherche de sorte que l'objet n'est pas
accessible à l'avenir, c'est très bien.
Je veux libérer l'objet de la cache.
Maintenant comment détruire/gratuit mutex correctement ?
pthread_mutex_destroy document nous dit de ne pas utiliser le pthread_mutex_destroy tandis que le mutex est verrouillé. Disons un thread décide de détruire l'objet qu'il a besoin de détruire l'
de verrouillage de sorte qu'il libère le verrou et un pthread_mutex_destroy. Ce qui arrive aux autres threads en attente pour les objets de verrouillage ?
Voici le code pour simuler la remarque ci-dessus , j'ai utilisé du sommeil(2) pour magnifier l'effet de
de course .
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
typedef struct exampleObj {
pthread_mutex_t mutex;
int key;
int value1;
int value2;
}exampleObj;
exampleObj sharedObj = {PTHREAD_MUTEX_INITIALIZER,0,0,0};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
exampleObj* Lookup(int key) {
return &sharedObj;
}
void* thrFunc(void* id) {
int i = (*((int*)id));
char errBuf[1024];
exampleObj * obj = Lookup(0);
if (pthread_mutex_lock(&obj->mutex)) {
printf("Locking failed %d \n",i);
return NULL;
}
//Do something
printf("My id %d will do some work for 2 seconds.\n",i);
sleep(2);
pthread_mutex_unlock(&obj->mutex);
int errNum = pthread_mutex_destroy(&obj->mutex);
strerror_r(errNum,errBuf,1024);
printf("Destroying mutex from thread %d : %s\n ",errNum,errBuf);
return NULL;
}
int main() {
pthread_t thrds[10];
int i;
int args[10];
char errBuf[1024];
int errNum = 1;
for (i=0;i<10;i++){
args[i] = i;
pthread_create(&thrds[i],NULL,thrFunc,args+i);
}
for (i=0;i<10;i++){
pthread_join(thrds[i],NULL);
}
return 0;
}
Plusieurs threads réussit à détruire le mutex. Et les autres threads accrocher pour toujours.
Gdb montre ces threads sont en attente pour le verrouiller.
Pas dans la vraie application il l'habitude de travailler comme ça. Utilisation réelle sera la recherche de l'objet et à le lire ou écrire verrou de l'objet et de l'utilisation et de libérer le verrou. J'ai voulu tester juste la partie où un thread par exemple est à court d'espace de cache, il a besoin de détruire un objet dans l'ordre de ramener quelques autres objets dans le cache. C'est le scénario que j'avais un doute , il suffit donc simulé ce scénario sommeil(2) est, assurez-vous il y avait assez de temps pour les autres threads d'attendre de verrouillage , de sorte que cela simule détruire quand les autres threads sont en attente.
OriginalL'auteur Sridhar V | 2013-06-18
Vous devez vous connecter pour publier un commentaire.
Le problème de base que vous avez est que la suppression d'un objet de la cache est quelque chose qui nécessite une synchronisation au niveau de cache, pas le niveau de l'objet.
Une façon de mettre en œuvre c'est en ayant un verrou global pour l'ensemble de la cache qui n'a lieu qu'au cours de recherches, et a chuté une fois de l'objet de verrouillage a été acquis. Ce verrou peut être un lecteur-écrivain de verrouillage, tenue pour l'écriture que si un thread est d'aller retirer l'objet. Si un thread qui souhaite utilisation un objet du cache:
et un thread qui souhaite détruire un objet du cache:
(où le
Remove()
fonction supprime la fonction de la mémoire cache de sorte que desLookup()
fonctions ne peuvent pas retourner).Oui, c'est la façon dont c'est fait, bonne explication.
OriginalL'auteur caf
C'est un comportement indéfini (un) de tenter de détruire un mutex verrouillé, ou (b) la référence a détruit mutex autre que d'appeler
pthread_mutex_init
à recréer (Voir la documentation). Cela signifie que le thread qui a détruit votre partagée mutex va faire la course avec les autres de la fermeture, et soit (1) à la destruction qui se passe en premier, les autres threads invoquer un comportement indéfini essayer de verrouillage en raison de (b) ou (2) de verrouillage dans un autre thread qui se passe en premier et en détruisant thread invoque un comportement indéfini à cause de (un).Vous avez besoin de changer votre conception de sorte qu'un mutex actives dans le cadre de la contention n'est jamais détruit. Pour votre exemple, vous risquez de détruire l'partagé mutex dans
main
après tous les threads sont joints. Pour le programme que vous décrivez, vous avez probablement besoin d'insérer un compteur de référence dans les objets.OriginalL'auteur Casey
Bien j'espère obtenir votre intention droite, j'ai eu exactement le même problème. De toute façon je me suis rendu compte plus tard que j'étais stupide: se Plaindre d'un comportement indéterminé de
pthread_mutex_*
fonctions aprèspthread_mutex_destroy()
est comme se plaindre deSEGFAULTS
lors de l'accès à un pointeur aprèsfree()
.Plupart des programmes en C sont modélisées autour du paradigme que chaque programme doit faire en sorte que la mémoire n'est pas accessible après une sorte de destruction. Bon C programmes ont un design qui empêche les pointeurs de se répandre partout, de sorte que la destruction arrive seulement à des endroits bien définis, lorsqu'aucune autre variable contient un pointeur de plus. Ce n'est pas du tout un sujet de préoccupation dans les ordures collectées langues.
Solution 1: Utilisation de compteurs refcount comme c'est le cas pour l'allocation de mémoire. Le refcounter est accessible via atomique fonctions. (Utiliser la glib, il contient un grand, portable etc)
Solution 1b: Utilisation de compteurs refcount comme c'est le cas pour l'allocation de mémoire, sperate les types de travailleurs qui sont importantes de celles qui ne le sont pas et utiliser de faibles références au plus tard, afin qu'ils n'empêchent pas l'objet de destruction.
Solution 2: Ne pas détruire le mutex. Pourquoi s'embêter avec la sauvegarde de la RAM? Il suffit de faire un mondial tableau statique comme 128k objets. Ajouter un struct membre qui indique l'état de l'objet.
Au lieu de destruction juste atomique de comparer et de définir la variable d'état, et d'imprimer une erreur dans les filets que l'accès à un objet en "DÉSACTIVÉ".
Solution 3 - La dure: ne faites pas de mémoire partagée de la simultanéité. Combiner un pool de threads qui correspond au nombre de Processeurs sur le système, l'utilisation non-bloquant IO, message d'objets et de machine d'état de conception. Faire des files d'attente de messages pour chaque tâche, et de laisser les tâches de communiquer uniquement par des messages mis en file d'attente dans la file d'attente de l'autre. Mettre la file d'attente dans la même "sélectionner" ou "pollfd' ensemble qui contient les sockets/filedescriptors. Mélanger le big data (jeu en 3d) entre les machines d'état, utiliser une structure atomique refcounter et copie sur écriture de la sémantique.
Ce sera dans la plupart des cas, être le plus performant, stable et facile à entretenir solution.
Si ce que vous faites n'a rien à voir avec la performance, réfléchir à deux fois sur l'utilisation des opérations atomiques. Ils peuvent être plus chers que les mutex.
OriginalL'auteur sheyll
Je ne pouvais pas être plus d'accord avec la caf sur ce. Nous avons fait quelque chose de semblable dans certaines de mise en œuvre (par exemple, reportez-vous ifData_createReference & ifData_removeReference routines dans ifMIB.c). L'idée de base est de garder un verrou global pour la garde de l'ensemble de la liste des objets et du niveau de l'objet de verrouillage pour la garde d'inscription dans la liste.
Lorsque nous avons pour créer une nouvelle entrée dans la liste, de prendre le verrou en ÉCRITURE sur la liste et d'ajouter une nouvelle entrée, de sorte que l'entrée est ajoutée de façon uniforme à tous les utilisateurs de la liste. Et la libération de la liste de verrouillage.
Lorsque nous devons regarder au-up/accès à une entrée de la liste, de prendre un verrou en LECTURE sur la liste et recherchez l'entrée. Une fois que nous trouvons l'entrée, prendre de l'objet de verrouillage en mode LECTURE pour les opérations en lecture seule /de la prise de l'objet de verrouillage en ÉCRITURE en mode de modification de l'entrée de l'objet. Maintenant, relâchez la liste de verrouillage. Maintenant, une fois que nous en aurons fini avec le traitement de l'entrée de l'objet de libération de l'objet de verrouillage.
Lors de l'entrée de l'objet doit être retiré de la liste, de prendre un verrou en ÉCRITURE sur la liste. Rechercher et trouver l'entrée de l'objet dans la liste. Prendre un verrou en ÉCRITURE sur l'entrée de l'objet, cela permettra d'assurer que vous êtes le SEUL utilisateur de l'objet. Maintenant, supprimez l'entrée de la liste, comme nul ne peut recherche plus dans la liste. Et la libération de l'objet de verrouillage immédiatement. Ensuite, relâchez la liste de verrouillage. Maintenant détruire l'objet et de libérer l'objet de ressources.
OriginalL'auteur NES