C ++ Vector, сбой push_back из другого потока? - PullRequest
6 голосов
/ 10 декабря 2010

У меня неожиданные ошибки в утверждениях в моем коде с использованием проверенной имплантации STL.

После некоторых исследований я сузил проблему до push_back в векторе, вызываемом из потока, отличного от того, в котором был создан вектор.

Простейший код для воспроизведения этой проблемы:

class SomeClass
    {
    private:
        std::vector<int> theVector;
    public:
        SomeClass () 
        {
            theVector.push_back(1); // Ok
        }


        void add()
     {
          theVector.push_back(1); // Crash 
     }
};

Единственное отличие состоит в том, что SomeClass создается из моего основного потока, а add вызывается из другого потока. Тем не менее, нет никакой проблемы с параллелизмом: в простейшей форме кода, которую я использовал для устранения неполадок, никто не читает или пишет из этого вектора, кроме случаев, которые я упомянул выше.

Отслеживая код push_back, я заметил, что некоторые методы из std :: vector, такие как count () или size (), возвращают мусор при вызове из другого thred (метод "add") и корректные значения при вызове из поток создания (например, в конструкторе)

Должен ли я заключить, что std :: vector не может использоваться в многопоточной среде? Или есть решение этой проблемы?

РЕДАКТИРОВАТЬ: удалены летучие

РЕДАКТИРОВАТЬ 2: Как вы думаете, возможно, что проблема не заключается в многопоточности? В моем тестовом прогоне add вызывается только один раз (проверяется с помощью точки останова). Если я удаляю push_back из конструктора, я все равно вылетает. Таким образом, в конце концов, даже при одном вызове метода вектора функция, вызываемая один раз, делает утверждение неудачным. Следовательно, не может быть совпадения или ...?

Ответы [ 4 ]

8 голосов
/ 10 декабря 2010

std::vector определенно может использоваться в многопоточной среде, если вы не обращаетесь к вектору из двух потоков одновременно.Я делаю это все время без проблем.

Поскольку vector не проблема, вам нужно более внимательно изучить механизм синхронизации, так как это, скорее всего, проблема.Я заметил, что вы пометили vector как volatile.Ожидаете ли вы, что volatile обеспечит синхронизацию?Потому что это не так. См. Здесь для получения дополнительной информации .

РЕДАКТИРОВАТЬ: Первоначально предоставлена ​​неправильная ссылка.Это сейчас исправлено.Извините за путаницу.

2 голосов
/ 10 декабря 2010

Если вы можете гарантировать, что никто не пишет или читает из вектора при вызове push_back, нет никаких причин, по которым он должен завершиться неудачей. Вы можете иметь дело с повреждением памяти более высокого уровня. Вы должны убедиться, что «this» указывает на подлинный экземпляр SomeClass, проверить его другие члены и т. Д.

1 голос
/ 10 декабря 2010

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

1 голос
/ 10 декабря 2010

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

Кроме того, вы можете добавить несколько сообщений журнала, как показано в следующем коде:

class SomeClass
    {
    private:
        volatile std::vector<int> theVector;
    public:
        SomeClass () 
        {
            std::cout << "SomeClass::SomeClass" << std::endl;
            theVector.push_back(1); // Ok
        }
        ~SomeClass ()
        {
            std::cout << "SomeClass::~SomeClass" << std::endl;
        }
        void add()
        {
            std::cout << "SomeClass::add" << std::endl;
            theVector.push_back(1);
        }
};

Убедитесь, что экземпляр SomeClass все еще существует при вызове функции add.

...