2010-06-09 7 views
2

Je vais avoir des problèmes avec un programme en utilisant pthreads, où les accidents occassional se produisent, qui pourraient être liés à la façon dont les fils fonctionnent sur des donnéesComment utiliser en toute sécurité les paramètres dans les threads, en utilisant C++ & Pthreads?

J'ai quelques questions de base sur la façon de programmer l'utilisation de threads, et la mise en page de mémoire :

Supposons qu'une fonction de classe publique effectue certaines opérations sur certaines chaînes et renvoie le résultat sous forme de chaîne. Le prototype de la fonction pourrait ressembler à ceci:

std::string SomeClass::somefunc(const std::string &strOne, const std::string &strTwo) 
{ 
//Error checking of strings have been omitted 
std::string result = strOne.substr(0,5) + strTwo.substr(0,5); 
return result; 
} 
  1. Est-il exact de supposer que les chaînes, être dynamique, sont stockés sur le tas, mais une référence à la chaîne est allouée sur la pile lors de l'exécution ?

Stack: [Certains mem addr] adresse de pointeur à l'endroit où la chaîne est sur le tas

Heap: [Certains mem addr] mémoire alloué à la chaîne initiale qui peut augmenter ou diminuer

Pour le fil de sécurité de fonctionnement, la fonction est étendue avec le mutex suivant (qui est déclarée comme privée dans le « SomeClass ») verrouillage:

std::string SomeClass::somefunc(const std::string &strOne, const std::string &strTwo) 
{ 
pthread_mutex_lock(&someclasslock); 

//Error checking of strings have been omitted 
std::string result = strOne.substr(0,5) + strTwo.substr(0,5); 

pthread_mutex_unlock(&someclasslock); 

return result; 
} 
  1. Est-ce un moyen sûr de verrouiller les opérations en cours sur les cordes (trois), ou un fil pourrait être arrêté par le planificateur dans les cas suivants, qui Je suppose assumerait la logique prévue:

    a. Juste après l'appel de la fonction, et les paramètres: strOne & strDeux ont été définis dans les deux pointeurs de référence que la fonction a sur la pile, le planificateur enlève le temps de traitement pour le thread et laisse un nouveau thread, ce qui écrase la référence Des pointeurs sur la fonction, qui à nouveau sont arrêtés par le planificateur, laissant le premier thread en arrière?

    b. Peut même se produire avec la chaîne « résultat »: la première chaîne construit le résultat, déverrouille le mutex, mais avant de retourner le planificateur laisse dans un autre thread qui exécute tout cela est un travail, en écrasant le résultat etc.

Ou est-ce que les paramètres de référence/la chaîne de résultats sont poussés sur la pile pendant qu'un autre thread effectue sa tâche?

  1. est le moyen sûr/correct de faire cela dans les discussions, et « retour » En conséquence, de passer une référence à une chaîne qui sera rempli avec le résultat à la place:

    SomeClass vide :: somefunc (const std :: string & STRONE, const std :: string & strTwo, std :: string result) { pthread_mutex_lock (& de someclasslock); // La vérification d'erreur des chaînes a été omise. result = strOne.substr (0,5) + strTwo.substr (0,5);

    pthread_mutex_unlock (& someclasslock); }

La logique prévue est que plusieurs objets de la classe crée de nouveaux « SomeClass » fils et passe des objets eux-mêmes en tant que paramètres, puis appelle la fonction: « someFunc »:

int SomeClass::startNewThread() 
{ 

pthread_attr_t attr; 
pthread_t pThreadID; 

if(pthread_attr_init(&attr) != 0) 
    return -1; 

if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) 
    return -2; 

if(pthread_create(&pThreadID, &attr, proxyThreadFunc, this) != 0) 
    return -3; 

if(pthread_attr_destroy(&attr) != 0) 
    return -4; 

return 0; 
} 

void* proxyThreadFunc(void* someClassObjPtr) 
{ 
return static_cast<SomeClass*> (someClassObjPtr)->somefunc("long string","long string"); 
} 

Désolé pour la longue description. Mais j'espère que les questions et l'intention sont claires, sinon faites le moi savoir et je vais élaborer.

Cordialement. Chris

Répondre

1

1 a/b: Non, aucun des deux ne peut se produire. Les paramètres des fonctions et leurs valeurs de retour sont situés sur la pile et chaque thread a sa propre pile. Cependant, d'autres choses peuvent certainement vous tromper:

  • l'une des opérations de chaîne pourrait lancer une exception, ce qui empêche someclasslock de jamais obtenir déverrouillé et votre application se bloque.
  • en supposant que les chaînes passées dans la fonction sont partagées entre threads (si elles ne le sont pas, le verrou est inutile), un autre thread pourrait appeler le destructeur juste après l'appel de la fonction et avant l'acquisition du verrou. Dans ce cas, l'opération de chaîne conduirait à un comportement indéfini.

Je vous recommande de créer un nouvel objet SomeClass pour chaque thread. Dans ce cas, tous les membres de ces objets ne sont accessibles que par un thread et n'ont pas besoin d'être protégés par un verrou. L'inconvénient serait que vous ne pouvez plus y accéder depuis votre thread principal après avoir démarré le nouveau thread. Si c'est nécessaire, alors vous devez les protéger avec un verrou (le verrou serait également un membre de cette classe). Cela dit, la fonction somefunc ne semble affecter aucun membre de l'objet et n'a donc pas besoin de protection. Pensez à la granularité du partage entre les threads, il me semble que le verrou de protection devrait être dans la fonction qui appelle somefunc.

+0

Merci à vous deux d'avoir pris le temps de répondre. – ChrisCphDK

0

Conseil général: Essayez de minimiser les endroits où l'accès aux données partagées peut se produire. Par données partagées, je veux dire les données qui peuvent être consultées à tout moment par n'importe quel fil.

Il existe des moyens généraux d'aborder la programmation multi-thread:

Producer consumer

Reader writers

Il y a bien sûr d'autres façons, mais ces deux sont les plus utilisés - au moins par moi (en particulier le premier).

Questions connexes