2010-08-25 4 views
2

Я разместил предыдущий вопрос "Seg Fault when using std::string on an embedded Linux platform", где я получил несколько полезных советов. С тех пор я отсутствовал в других проектах и ​​недавно вернулся к рассмотрению этой проблемы.Потокобезопасный векторный и строковый контейнер?

Чтобы повторить, я ограничусь использованием кросс-компилятора arm-linux (версия 2.95.2), поскольку это то, что поставляется и поддерживается поставщиком встроенной платформы. Я понимаю, что проблема, скорее всего, связана с тем, что stdlib очень старый, и не особенно безопасный поток.

Проблема в том, что всякий раз, когда я использую контейнеры STL в нескольких потоках, я получаю ошибку сегментации. В приведенном ниже коде будет последовательно обнаружена ошибка, если я не буду использовать pthread_mutex_lock и операторы области действия вокруг объявлений контейнера (как и в других сообщениях).

Невозможно использовать этот подход в моем приложении, поскольку я передаю контейнеры различным методам и классам. Я бы идеально хотел решить эту проблему или найти подходящую альтернативу. Я пробовал стандартную библиотеку шаблонов STLPort и SGI с теми же результатами. Я могу только предположить, что, поскольку они связаны очень старым gcc, они не могут решить проблему.

Есть ли у кого-нибудь какие-либо возможные рекомендации или решения? Или, может быть, вы можете предложить реализацию вектора (и строки), который я могу вставить в свой код?

Заранее благодарим за любые указания.

#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

Возможный дубликат [Threadsafe Vector class для C++] (http://stackoverflow.com/questions/1099513/threadsafe-vector-class-for-c) – Glen

+1

Я в замешательстве - использование контейнеров выше полностью основанные на стеке (локальные переменные), поэтому сами контейнеры никогда не обращаются к потокам. И все-таки у вас все еще есть аварии? Это означает, что для простого создания контейнеров STL в стеке требуется синхронизация? Я никогда не слышал об этом ... –

+0

Майк, это мои мысли, и почему это вызывает у меня такую ​​головную боль. Я могу только предположить, что для некоторой оптимизации используются некоторые статические переменные, используемые в реализации, и именно это делает ее небезопасной. – Brad

ответ

2

Часть вашего запроса может потребоваться в another thread. На дизайн C++, включая стандартную библиотеку, влияет множество факторов. Эффективность - это повторяющаяся тема. Механизмы безопасности нитей часто противоречат целям эффективности. Возраст библиотеки на самом деле не проблема.

Для вашей ситуации вы можете обернуть вектор STL в свой собственный векторный класс (вы можете рассмотреть Decorator), который содержит механизм блокировки и предоставляет логику блокировки/разблокирования для доступа.

6

Проблема заключается не в контейнерах, а в коде.

Совершенно необязательно, чтобы сами контейнеры были потокобезопасными, потому что в первую очередь вам нужна транзакционная семантика.

Предположим, для демонстрации, что у вас есть потоковая реализация vector, например.

  • резьба 1: if (!vec.empty())
  • резьба 2: vec.clear();
  • резьба 1: foo = vec.front();

Это приводит к непредсказуемому поведению.

Проблема в том, что каждая операция в потоковом контейнере довольно бессмысленна, поскольку по-прежнему требуется возможность блокировки самого контейнера для нескольких операций в строке. Поэтому вы будете блокировать ваши различные операции, а затем снова блокировать каждую операцию?

Как я уже сказал, совершенно не нужно.

+2

Matthieu, я полностью понимаю, что вы говорите, и понимаете, что при совместном использовании экземпляра контейнера между потоками будет неопределенное поведение. Однако проблема, с которой я столкнулась, заключается в том, что локальные экземпляры стека наступают друг на друга. Зачем мне нужно блокировать локальную переменную? – Brad

+0

Может быть, если ваша схема распределения памяти не была потокобезопасной. Вполне возможно, что по умолчанию ваш компилятор использует не-threadafe 'malloc' /' new' и что он попадет в потокобезопасную версию, если вы передадите правильный вариант ... но теперь это далекое предположение. Что касается переменных 'static': код STL вполне читабельен, вы должны иметь возможность просматривать реализацию (например,« вектор »). –

Смежные вопросы