2016-02-05 3 views
0

Ниже приведен фрагмент более крупной программы и выполняется с использованием Pthreads.Список Iterator из библиотеки STL не работает

UpdateFunction читает из текстового файла. Функция FunctionMap используется только для вывода (ключ, 1). Здесь существенно обновляются функции UpdateFunction и FunctionMap для разных потоков.

queue <list<string>::iterator> mapperpool; 

void *UpdaterFunction(void* fn) { 
    std::string *x = static_cast<std::string*>(fn); 
    string filename = *x; 
    ifstream file (filename.c_str()); 
    string word; 
    list <string> letterwords[50]; 
    char alphabet = '0'; 
    bool times = true; 

    int charno=0; 

    while(file >> word) { 
     if(times) { 
      alphabet = *(word.begin()); 
      times = false; 
     } 
     if (alphabet != *(word.begin())) { 
      alphabet = *(word.begin()); 
      mapperpool.push(letterwords[charno].begin()); 
      letterwords[charno].push_back("xyzzyspoon"); 
      charno++; 
     } 
     letterwords[charno].push_back(word); 
    } 

    file.close(); 

    cout << "UPDATER DONE!!" << endl; 
    pthread_exit(NULL); 
} 

void *FunctionMap(void *i) { 
    long num = (long)i; 
    stringstream updaterword; 
    string toQ; 
    int charno = 0; 


    fprintf(stderr, "Print me %ld\n", num); 
    sleep(1); 

    while (!mapperpool.empty()) { 
     list<string>::iterator it = mapperpool.front(); 
     while(*it != "xyzzyspoon") { 
      cout << "(" << *it << ",1)" << "\n"; 
      cout << *it << "\n"; 
      it++; 
     } 
     mapperpool.pop(); 
    } 

    pthread_exit(NULL); 
} 

Если я добавить время (! Mapperpool.empty()) в UpdateFunction то это дает мне идеальный выход. Но когда я перехожу обратно в FunctionMap, это дает мне странный выход и Segfaults позже. Вывод при использовании в UpdateFunction: Распечатать меня 0 курс крышка класс культуры класс Колпачок курс курс крышка культура параллелизм .....

[Каждое слово в отдельной строке]

Выход при использовании в FunctionMap (снимок выше): Распечатать 0 UPDATER DONE !! (курс% 0 + 0 @ + 0 + 05P + 0 cap% + 0 + 0, 05 + 0 class5P? 0 xyzzyspoon% + 0 + 0 (+ 0% P, 0 ,�0�,�05+�0����class%p,�0�,�0-�05�,�0����cap%�,�0�,�0X-�05�,�0����course%-�0 -�0�-�050-�0����course% - 0p- 0 - 05 - 0 cap% - 0 - 0H . 05 - 0 culture% . 0. 0 . 05 . 0 concurrency% P. 0`. 0 . 05p. 0 course% . 0 . 08/05 . 0 cap% . 0/0/05/0 Неисправность сегрегации (сбрасываемая сердцевина)

Как сделать Я исправляю эту проблему?

+1

'while (* it! =" Xyzzyspoon ") it ++' Это очень подозрительно. Вам нужно как-то проверить конец списка. Кто гарантирует, что список содержит указанную строку? – bolov

+0

Список определенно не содержит эту строку. И даже если это так, я должен по крайней мере получить первые несколько символов, которых я не знаю. –

ответ

1

list <string> letterwords[50] является локальным для UpdaterFunction. Когда UpdaterFunction заканчивается, все его локальные переменные разрушаются. hen FunctionMap проверяет итератор, что итератор уже указывает на удаленную память. Когда вы вставляете while(!mapperpool.empty())UpdaterFunction ждет FunctionMap завершение и letterwords остается «живым».

1

Здесь по существу UpdateFunction и FunctionMap работают на разных потоках.

И поскольку оба они манипулируют один и тот же объект (mapperpool) и ни один из них использует либо pthread_mutex ни std::mutex (C++ 11), у вас есть гонки данных. Если у вас гонка данных, у вас есть Undefined Behavior, и программа может делать все, что захочет. Скорее всего, он напишет мусор по всей памяти, пока, в конце концов, не рухнет, как вы видите.

Как исправить эту проблему?

Заблокировав объект mapperpool.

Почему этот список не является потокобезопасным?

Ну, в подавляющем большинстве случаев использование одного списка (или любой другой коллекции) не будет использоваться более чем одним потоком. В значительной части остальных замок должен будет распространяться более чем на одну операцию в коллекции, поэтому клиенту придется делать свою собственную блокировку в любом случае.Оставшийся крошечный процент случаев, когда помощь в самих операциях может помочь, не стоит добавлять накладные расходы для всех; Принцип разработки ключа C++ заключается в том, что вы платите только за то, что используете.

Коллекция только возвратные, а это означает, что с помощью различных экземпляров параллельно безопасно.

Обратите внимание на Pthreads

C++ 11 введена threading library который хорошо интегрируется с языком. В частности, он использует RAII для блокировки std::mutex через std::lock_guard, std::unique_lock и std::shared_lock (для блокировки считывающего устройства). Последовательно используя их, можно устранить большой класс блокирующих ошибок, которые в противном случае занимают много времени для отладки.

Если вы еще не можете использовать C++ 11 (на рабочем столе вы можете, но некоторые встроенные платформы еще не получили обновление компилятора), вы должны сначала рассмотреть Boost.Thread, так как он дает те же преимущества.

Если вы еще не можете использовать, попробуйте найти или написать простую обертку RAII для блокировки, например, C++ 11/Boost. Основная оболочка - это всего лишь пара строк, но это сэкономит вам много отладки.

Обратите внимание, что C++11 и Boost также атомную библиотеку операций, которые PThreads очень не хватает.

+0

Был отличный ответ! Благодаря! Это было присвоение класса. Основная цель задания заключалась в том, чтобы заставить студентов попробовать библиотеку Pthreads. –

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