crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в MSVS 2005 std::deque и boost 1.44.0 boost::mutex::scoped_lock
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
Теги
Выровнять по центру
Ссылка на тему
Ссылка на сообщение
Скрытый текст
Сокращение
Код с подсветкой
Offtopic
 
Удалить форматирование
Спец. элементы
Шрифт
Размер
 
Цвет шрифта
 
Отменить ввод
Вернуть ввод
Полужирный
Курсив
Подчеркнутый
 
 
Смайлики
Вставить изображение
Вставить адрес электронной почты
Цитата
Код
Раскрывающийся текст
 
Увеличить отступ
По левому краю
По центру
По правому краю
Вставить список
Вставить список

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Iron Bug Дата 6.10.2010, 9:43
  ВНИМАНИЕ, БАГА В MS STL!
Подсказали мне в листе рассылок буста, в чём проблема с deque и многопоточностью (thanks to David Ward):

Bug in std::deque. Non-conforming invalidation of iterators after pop_front()

Вкратце: не юзайте std::deque в MSVS начиная с 2005 и заканчивая 2010. Метод pop_front() иногда даёт сбой и портит итераторы элементов, к которым он не имеет никакого отношения. А в моём случае то же самое делал push_front() . Одного поля ягодки! Видимо, проявление баги зависит от таймингов: когда начинается частое обращение (даже защищённое мьютексами!) - что-то кривеет и некоторые итераторы становятся невалидными.

Мелкософт обещает стать хорошим и исправить багу в студии 2011. А пока что лучше не рисковать и вообще не юзать std::deque.

А вот с конструктором boost::thread пока неясно...

P.S. Гнусности ещё только начинаются! Теперь для начала нужно пересобрать стопицот старых, но вполне используемых проектов, чтобы избавиться от использования std::deque (а сначала ещё надо найти, на что бы такое его заменить!). Но кроме этого я вдруг обнаружила, что исходники boost также содержат этот злополучный deque и некоторые библиотеки потенциально опасны при работе под компилером MSVС версий от 7-й до 10-й. В частности, deque используется в исходниках бустовских библиотек smart_ptr (sp_collector.cpp), boost:expressive и boost::regex (command_line.cpp). И в заголовочниках некоторых библиотек буста есть #include <deque>.... Одним словом, приличная такая "жожоба", как мы выражались на одной работе.
Iron Bug Дата 1.10.2010, 12:10
  чёрт, да что сегодня за день за такой?
стала проверять под MSVS 2010, а там вообще boost::thread падает с access violation в конструкторе!
буст тот же, 1.44.0.

причём на StackOverflow пишут, что это бага 43-го буста и что она даже была пофиксена (http://stackoverflow.com/questions/2914666...ption-in-vs2010), но вот у меня прецедент с 44-м бустом. и в списках багов буста я вроде не нашла этой баги... пороюсь в мэйл-рассылке буста, может там есть что-то насчёт этого.

версия MSVS такая:
Version 10.0.30319.1 RTMRel
Installed Version: Premium

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

пока неясно, куда сообщать о проблеме. буду ещё экспериментировать.
Алексей1153 Дата 1.10.2010, 10:04
  а если ради эксперимента написать свою следилку за разлочиванием - в конструкторе принимает указатель на синхро-объект, а в деструкторе разлочивает

Если всё будет в порядке, то глюк действительно в scoped_lock имеется
Iron Bug Дата 1.10.2010, 9:44
  Чуть не рехнулась, пока искала эту багу! Вроде всё правильно, а лезет эксепшн...
Использую MSVS 2005 SP1 и boost 1.44.0.

Суть в том, что мне нужен был дек(std::deque) для буферизации данных между несколькими потоками. В этот дек пишут несколько потоков и есть один читающий поток, который периодически обрабатывает данные и сбрасывает содержимое дека.

Чтобы не тормозить работу с деком, была огранизована система работы с указателями:
- существует указатель на объект дека (он инициализируется в начале работы программы, до запуска всех потоков)
- пишущие потоки добавляют данные, используя этот указатель
- читающий поток подменяет глобальный указатель на новый созданный объект , сбрасывает накопленное содержимое и затем освобождает использованный объект

Естественно, всё это происходит под мьютексами и собирается как многопоточное приложение.

Сначала были заюзаны локи boost:mutex::scoped_lock. Я их обычно использую где ни попадя: удобны, безопасны для эксепшнов и т.п. Но вот тут и оказалась засада: при нескольких пишущих потоках вылезал эксепшн нарушения стека. Позже при тестировании выяснилось, что та же беда случается и при нескольких читающих потоках, даже при одном пишушем. Я уже думала, что у меня крыша поехала: ну нет ничего подозрительного, всё под мьютексами... потом решила наобум заменить scoped_lock на простые lock/unlock... и оно заработало!!!

Написала тестовую софтинку, бага(нарушение стека) отчётливо проявляется при установке макросов NUMBER_OF_WRITERS_1 или NUMBER_OF_WRITERS_1 в число больше единицы. При этом NUMBER_OF_WRITERS_2 и NUMBER_OF_READERS_2 могут быть абсолютно любыми - никаких проблем не возникает.
Раскрывающийся текст

#include <deque>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/barrier.hpp>

using namespace std;
using namespace boost;

// число потоков со scoped_lock
// тест падает, если хотя бы один из них больше 1
#define NUMBER_OF_WRITERS_1        1
#define NUMBER_OF_READERS_1        1

// число потоков с lock/unlock
// может быть любое число потоков
#define NUMBER_OF_WRITERS_2        2
#define NUMBER_OF_READERS_2        2

typedef deque<long> deq_type;

// указатель на общий дек
deq_type *pdeq;

// мьютекс для защиты дека
mutex mt;

// барьеры используются для одновременного старта всех потоков
barrier barr1(NUMBER_OF_WRITERS_1+NUMBER_OF_READERS_1);
barrier barr2(NUMBER_OF_WRITERS_2+NUMBER_OF_READERS_2);

// флаг завершения работы потоков
bool stop_flag;

// заглушка 
void dummy()
{
}

// пишуший поток со scoped_lock
void writer1()
{
    barr1.wait();
    while(!stop_flag)
    {
        {
            mutex::scoped_lock(mt);
            pdeq->push_front(1);
        }
        this_thread::sleep(posix_time::milliseconds(10));
    }
}

// читающий поток со scoped_lock
void reader1()
{
    deq_type *pcopy;
    barr1.wait();
    while(!stop_flag)
    {
        if(pdeq->size() > 0)    
        {
            {
                mutex::scoped_lock(mt);
                pcopy = pdeq;
                pdeq = new deq_type();
            }

            deque<long>::iterator i;
            for(i=pcopy->begin(); i!=pcopy->end(); i++)
            {
                dummy();
            }

            pcopy->clear();
            delete pcopy;
        }
    }
    this_thread::sleep(posix_time::milliseconds(10));
}

// пишуший поток со lock/unlock
void writer2()
{
    barr2.wait();
    while(!stop_flag)
    {
        mt.lock();
        pdeq->push_front(1);
        mt.unlock();
        this_thread::sleep(posix_time::milliseconds(10));
    }
}

// читающий поток со lock/unlock
void reader2()
{
    deq_type *pcopy;
    barr2.wait();
    while(!stop_flag)
    {
        if(pdeq->size() > 0)    
        {
            mt.lock();
            pcopy = pdeq;
            pdeq = new deq_type();
            mt.unlock();

            deque<long>::iterator i;
            for(i=pcopy->begin(); i!=pcopy->end(); i++)
            {
                dummy();
            }

            pcopy->clear();
            delete pcopy;
        }
    }
    this_thread::sleep(posix_time::milliseconds(10));
}

int main()
{
    thread_group tg;

    // тест со scoped_lock
    // инициализируем дек
    pdeq = new deq_type();

    stop_flag = false;
    for(int i=0; i<NUMBER_OF_WRITERS_1; i++) tg.create_thread(writer1); 
    for(int i=0; i<NUMBER_OF_READERS_1; i++) tg.create_thread(reader1); 

    this_thread::sleep(posix_time::seconds(1));
    stop_flag = true;
    tg.join_all();

    if(pdeq != 0) 
    {
        pdeq->clear();
        delete pdeq;
    }

    // тест с lock/unlock

    // инициализируем дек
    pdeq = new deq_type();

    stop_flag = false;
    for(int i=0; i<NUMBER_OF_WRITERS_2; i++) tg.create_thread(writer2);
    for(int i=0; i<NUMBER_OF_READERS_2; i++) tg.create_thread(reader2);

    this_thread::sleep(posix_time::seconds(1));
    stop_flag = true;
    tg.join_all();

    if(pdeq != 0) 
    {
        pdeq->clear();
        delete pdeq;
    }
    return 0;
}


Вроде ошибок я не вижу. Не первый год пишу многопоточные приложения... То ли баг буста, то ли STL. Нужно дополнительно проверять. Завтра соберу буст под MSVS 2010 и проверю. А дома под линём проверю...

Может, кто-то сталкивался с подобной хренью?

P.S. модераторы, поправьте в названии stl::deque на std::deque
P.P.S чуть подправила код (быстро копировала, забыла вторую инициализацию), но суть баги не меняется.
Просмотр темы полностью (откроется в новом окне)
RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 11.7.2025, 7:24