2016-06-08 1 views
2

j'ai un morceau de code où j'ai quelque chose comme:programme s'écraser au hasard en raison d'appel gratuit() dans plusieurs threads

int *mem_ptr; 
. 
. 
if(mem_ptr) 
{ 
    free(mem_ptr); 
} 
. 
. 

L'application est multi-thread. Parfois, ce qui se passe est un thread passe le if vérifier et puis avant le changement de contexte free() se produit et un autre thread passe également le if vérifier et également le free(). Maintenant, lorsque le contrôle revient au premier thread il se bloque à free() donnant l'erreur Abort message: 'invalid address or address of corrupt block 0x40735cb0 passed to dlfree'.

Autre que mutex, est-il une meilleure façon de gérer cette situation

PS: Je travaille sur Android classeurs natifs en C++ et ce morceau de code est dans l'appel onTransact().

+2

Tu ne peux pas utiliser shared_ptr? Si ce n'est pas le cas, la mise en œuvre d'un mécanisme compté par ref utilisant des incréments et des décréments atomiques en valait la peine. – Arunmu

+2

Arunmu a raison - votre logique est intrinsèquement brisée non seulement à cause des multiples possibles, mais aussi parce qu'un thread peut libérer le point-to-memory alors qu'un autre thread continue à l'utiliser (ne l'ayant pas encore fait). La réponse de Jeegar à propos de la création de l'atomique 'free (mem_ptr)' n'est pas suffisante pour obtenir du code fiable. –

+0

Assurez-vous que le mem est alloué via malloc – David

Répondre

0

Deux choses:

opération

1) free doit être atomique. Donc, utilisez n'importe quel mécanisme comme mutex, sémaphore, etc.

2) Après l'appel free(), mettez explicitement à jour votre pointeur vers NULL. Donc, dans le deuxième fil, il ne donnera pas if()

S'il vous plaît noter: free() appel après la mémoire de fente n'attribuera pas NULL à votre pointeur.

+0

C'est tout le point. Même si j'attribue la valeur NULL, les deux threads sont entrés dans les contrôles .... donc cela n'aidera pas dans certains cas. Cela dépend où le changement de contexte se produit. Mutex est définitivement la solution. C'est ce que j'ai écrit dans ma question. –

+0

@InsaneCoder, non, le pointeur 'free' from' NULL' fonctionne bien. Il n'y a donc pas de problème si quelques threads sont entrés dans ce bloc. Mais 'free' et le pointeur sur NULL doivent être atomiques. – Arkady

1

Si deux threads ou plus tentent de libérer/supprimer la même mémoire, le code et le design sont rompus. Alors que le threading des primitives de synchronisation aiderait, je ne les utiliserais pas non plus. Il devrait y avoir juste un fil libérant la mémoire. Il devrait idéalement être celui qui a alloué la mémoire. S'il est différent, comme dans le cas d'un passage de message croisé, seul le thread cible un devrait supprimer la mémoire. C'est comme dire qu'un thread ouvre un fichier et que n'importe quel thread le ferme. Ça n'a pas l'air bien. La fermeture du fichier doit être effectuée par un thread unique, et non par plusieurs threads en contention.

0

Parce que free de NULL fonctionne bien, ne rien faire, utilisez que:

int *mem_ptr(NULL); 
. 
. 
if(mem_ptr) 
{ 
    //any multithreaded lock guard have to be here 
    free(mem_ptr); 
    mem_ptr = NULL; 
} 

Alors, seule chose que vous devez prendre soin, est que les opérations free et pointeur de réglage à NULL doivent être atomiques. Cela signifie que tous les autres threads ne doivent pas effectuer ces opérations avant la fin de l'opération, ce qui signifie utiliser des objets de synchronisation de base.

+0

L'emplacement du verrou doit être _avant_ le 'if'. Le code proposé est une variante du schéma de verrouillage à double vérification. – MSalters

+0

mais quel est le problème si le deuxième thread entrera 'if', alors attendez que le premier thread libère la mémoire et placez le pointeur sur' NULL', puis appelez 'free' de NULL, et réécrivez le pointeur sur' NULL'? – Arkady

+0

Le problème est que l'appel 'free (mem_ptr)' sur le second thread n'appelle pas 'free (NULL)', il appelle 'free (mem_ptr)'. Le fait que vous définissiez 'mem_ptr' à' NULL' sur un autre thread est sans importance lorsque vous n'avez pas correctement protégé l'accès à 'mem_ptr'. Comme vous faites une vérification non protégée de 'if (mem_ptr)', le compilateur peut supposer qu'aucun autre thread ne le modifie. Mettre le verrou au bon endroit indique au compilateur que 'mem_ptr' est partagé, que d'autres threads peuvent y écrire, et qu'il ne peut donc être placé que dans un registre dans la portée de ce verrou. – MSalters

0

Vous pouvez affecter le pointeur à NULL comme expliqué dans les autres réponses ... mais cela ne garantit toujours pas le succès. Deux threads peuvent passer à la fois et appeler free() l'un après l'autre, puis assigner à NULL après cela .... mais trop tard car votre programme pourrait bien avoir crashé.

Vous devez utiliser des mécanismes de synchronisation de fil ici comme un mutex:

std::mutex mtx;   // declare mutex for critical section 
    : 
    : 
mtx.lock(); // only one thread will get inside here... 
if(mem_ptr) 
{ 
    //any multithreaded lock guard have to be here 
    free(mem_ptr); 
    mem_ptr = NULL; 
} 
mtx.unlock(); // release the mutex...