2010-08-25 9 views
2

J'ai posté une question précédente "Seg Fault when using std::string on an embedded Linux platform" où j'ai reçu des conseils très utiles. Depuis lors, je suis parti pour d'autres projets et je suis récemment revenu sur cette question.Un vecteur thread-safe et un conteneur de chaînes?

Pour réitérer, je suis limité à l'utilisation du compilateur croisé arm-linux (version 2.95.2) car c'est ce qui est fourni et pris en charge par le fournisseur de plate-forme intégrée. Je comprends que le problème est probablement dû au fait que le fichier stdlib est très ancien et qu'il n'est pas particulièrement sécurisé. Le problème est que chaque fois que j'utilise les conteneurs STL dans plusieurs threads, je me retrouve avec un défaut de segmentation. Le code ci-dessous va régulièrement segmenter à moins que j'utilise pthread_mutex_lock et les opérateurs de portée autour des déclarations de conteneur (comme dans un autre post).

Il n'est pas possible d'utiliser cette approche dans mon application lorsque je fais passer les conteneurs à différentes méthodes et classes. Je voudrais idéalement résoudre ce problème, ou trouver une alternative appropriée. J'ai essayé STLPort et Standard Template Library de SGI avec les mêmes résultats. Je ne peux que supposer que parce qu'ils sont liés par le très vieux gcc, ils ne peuvent pas résoudre le problème.

Est-ce que quelqu'un a des recommandations ou des solutions possibles? Ou peut-être pouvez-vous suggérer une implémentation de vector (et string) que je peux faire tomber dans mon code?

Merci d'avance pour toute indication.

#include <stdio.h> 
    #include <vector> 
    #include <list> 
    #include <string> 

    using namespace std; 
    ///////////////////////////////////////////////////////////////////////////// 

    class TestSeg 
    { 
    static pthread_mutex_t  _logLock; 
    public: 
     TestSeg() 
     { 
     } 

     ~TestSeg() 
     { 
     } 

     static void* TestThread(void *arg) 
     { 
     int i = 0; 
     while (i++ < 10000) 
     { 
     printf("%d\n", i); 
     WriteBad("Function"); 
     } 
     pthread_exit(NULL); 
     } 

     static void WriteBad(const char* sFunction) 
     { 
     //pthread_mutex_lock(&_logLock); 
     //{ 

     printf("%s\n", sFunction); 
     string sKiller;  //  <----------------------------------Bad 
     //list<char> killer; //  <----------------------------------Bad 
     //vector<char> killer; //  <----------------------------------Bad 

     //} 
     //pthread_mutex_unlock(&_logLock); 

     return; 
     } 

     void RunTest() 
     { 
     int threads = 100; 
     pthread_t  _rx_thread[threads]; 
     for (int i = 0 ; i < threads ; i++) 
     { 
     pthread_create(&_rx_thread[i], NULL, TestThread, NULL); 
     } 

     for (int i = 0 ; i < threads ; i++) 
     { 
     pthread_join(_rx_thread[i], NULL); 
     } 
     } 

    }; 

    pthread_mutex_t  TestSeg::_logLock = PTHREAD_MUTEX_INITIALIZER; 

    int main(int argc, char *argv[]) 
    { 
    TestSeg seg; 
    seg.RunTest(); 
    pthread_exit(NULL); 
    } 
+0

duplication possible de [classe Vector Threadsafe pour C++] (http://stackoverflow.com/questions/1099513/threadsafe-vector-class-for-c) – Glen

+1

Je suis confus - l'utilisation des conteneurs ci-dessus est entièrement basé sur la pile (variables locales), les conteneurs eux-mêmes ne sont jamais accessibles à travers les threads. Et pourtant, vous avez toujours des plantages? Cela implique que la simple création de conteneurs STL sur la pile nécessite une synchronisation? Je n'ai jamais entendu parler d'une telle chose ... –

+0

Mike, exactement mes pensées, et pourquoi cela me cause un tel mal de tête. Je peux seulement supposer qu'il y a des variables statiques utilisées dans l'implémentation pour une optimisation, et c'est ce qui la rend peu sûre. – Brad

Répondre

2

Une partie de votre requête peut répondre à another thread. La conception de C++, y compris la bibliothèque standard, est influencée par de nombreux facteurs. L'efficacité est un thème répété. Les mécanismes de sécurité des filetages sont souvent en contradiction avec un objectif d'efficacité. L'âge de la bibliothèque n'est pas vraiment le problème. Pour votre situation, vous pouvez peut-être envelopper le vecteur STL dans votre propre classe de vecteurs (vous pouvez envisager un Decorator) qui contient le mécanisme de verrouillage et fournit la logique de verrouillage/déverrouillage autour des accès.

6

Le problème n'est pas avec les conteneurs, c'est avec votre code.

Il est totalement inutile de sécuriser les conteneurs, car ce dont vous avez besoin, avant tout, c'est une sémantique transactionnelle. Supposons, pour des raisons de démonstration, que vous avez une implémentation threadsafe de vector, par exemple.

  • Discussion 1: if (!vec.empty())
  • Discussion 2: vec.clear();
  • Discussion 1: foo = vec.front();

Cela conduit à un comportement non défini. Le problème est que le fait d'avoir chaque opération sur le threadsafe du conteneur est inutile puisque vous devez toujours pouvoir verrouiller le conteneur lui-même pour plusieurs opérations d'affilée. Par conséquent, vous verrouiller pour vos différentes opérations, puis verrouiller à nouveau sur chaque opération?

Comme je l'ai dit: complètement inutile.

+2

Matthieu, j'apprécie pleinement ce que vous dites et comprends qu'il y aurait un comportement indéfini lors du partage de l'instance du conteneur entre les threads. Cependant, le problème que je rencontre est que les instances de la pile locale marchent sur les autres orteils. Pourquoi aurais-je besoin de verrouiller une variable locale? – Brad

+0

Il pourrait être si votre schéma d'allocation de mémoire n'était pas threadsafe. Il est possible que par défaut votre compilateur utilise un 'malloc' /' new' non-threadsafe et qu'il obtiendra une version threadsafe si vous passez la bonne option ... mais maintenant c'est une supposition farfelue. Comme pour les variables 'static': le code STL est assez lisible, vous devriez pouvoir parcourir l'implémentation (de' vector' par exemple). –