crossplatform.ru

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

> MSVS 2005 std::deque и boost 1.44.0 boost::mutex::scoped_lock, разрушение стека при многопоточности
Iron Bug
  опции профиля:
сообщение 1.10.2010, 9:44
Сообщение #1


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Чуть не рехнулась, пока искала эту багу! Вроде всё правильно, а лезет эксепшн...
Использую 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 чуть подправила код (быстро копировала, забыла вторую инициализацию), но суть баги не меняется.

Сообщение отредактировал igor_bogomolov - 1.10.2010, 12:29
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.3.2024, 20:56