LinearHashTable iter не разыменовывается и iter не

Привет всем:)

Я использую 1.5.4-all (2014-10-22) в своем проекте VC++ (Microsoft Visual C++ Compiler 18.00.21005.1 для платформы x86).

Моя проблема в том, что через некоторое время я получаю следующее сообщение об ошибке. Время, по истечении которого возникает ошибка, значительно отличается - иногда это происходит через 30 секунд, а иногда и через 5 минут.

Я мог бы найти источник ошибки в файле LinearHashTable.h в строке 214:

У меня есть следующий метод, где Shot (структура) добавляется в таблицу:

    void ShotSimulationService::SimulateShot(Shot shot) {
        MutexThreadLock.lock();
        shots.insert(ShotsSetType::ValueType(SimulationShot(shot)));
        errorCount = 0;
        MutexThreadLock.unlock();
    }

Вызов SimulateShot из другого потока, чем обработка следующего кода:

    void ShotSimulationService::Update(WebcamService* observable) {
        if (shots.empty()) {
            return;
        }

        try {
            Mat frame = observable->GetLastImage().clone();
            ShotsSetType::Iterator iter = shots.begin();
            vector<Shot> deleteShots;
            errorCount++;
            while (iter != shots.end()){

                if (iter->SimulateStartExplosion()) {
                    //simulate gun explosion
                    OverlayImage(frame, gunShotImg, iter->startPoint);
                }

                //simulate explosion
                SimulationShot::SimulationHitStatus status = iter->status;
                if (status == SimulationShot::SimulationHitStatus::UNKNOWN) {
                    if (detectionService.HasShotHitPlayer(frame, *iter)) {
                        iter->status = SimulationShot::HIT_PLAYER;
                        iter->SetCurrentPointAsEndoint();

                        //Notify that player was hit
                        playerHitQueue.enqueueNotification(new PlayerHitNotification(iter->hitPlayer));
                    }
                }

                if (iter->SimulateEndExplosion()) {
                    if (status == SimulationShot::HIT_PLAYER) {
                        int explosionx = iter->endPoint.x - robotExplosionHalfXSize > 0 ? iter->endPoint.x - robotExplosionHalfXSize : 0;
                        int explosionY = iter->endPoint.y - robotExplosionHalfYSize > 0 ? iter->endPoint.y - robotExplosionHalfYSize : 0;
                        OverlayImage(frame, robotExplosionImg, Point2i(explosionx, explosionY));
                    }
                    else {
                        // status == SimulationShot::HIT_WALL or UNKNOWN
                        int explosionx = iter->endPoint.x - wallExplosionHalfXSize > 0 ? iter->endPoint.x - wallExplosionHalfXSize : 0;
                        int explosionY = iter->endPoint.y - wallExplosionHalfYSize > 0 ? iter->endPoint.y - wallExplosionHalfYSize : 0;
                        OverlayImage(frame, robotExplosionImg, Point2i(explosionx, explosionY));

                        if (status != SimulationShot::HIT_WALL) {
                            iter->status = SimulationShot::HIT_WALL;
                        }
                    }

                    if (iter->IsSimulationFinished()) {
                        deleteShots.push_back(*iter);
                    }
                }
                else {
                    //simulate bullet
                    OverlayImage(frame, cheeseImg, iter->GetNextShotPoint());
                }

                ++iter;
            }

            //delete finished simulations
            MutexThreadLock.lock();
            for each (Shot shot in deleteShots)
            {
                shots.erase(shot);
            }
            MutexThreadLock.unlock();
        }
        catch (cv::Exception& e) {
            Logger& logger = Logger::get("Test");
            logger.error(e.what());
        }
    }

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

Стоп вызова ошибки начинается в следующей строке:

    if (iter->SimulateEndExplosion()) {

В методе SimulateEndExplosion использовались только члены структуры:

        bool SimulateEndExplosion() {
            if (status == HIT_PLAYER) {
                currPercentage = 1.0;
                return true;
            }

            if (currPercentage < 1.0) {
                return false;
            }

            ++endExplosionCtr;
            return endExplosionCtr <= maxEndExplosions;
        }

У кого-нибудь есть идея, почему возникает эта проблема?

Любая помощь и любые отзывы приветствуются! Я абсолютно не знаю, что здесь происходит не так:(

Спасибо!

1 ответ

Решение

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

Кроме того, использование мьютекса небезопасно, поскольку мьютекс не будет разблокирован, если между lock() и unlock() будет сгенерировано исключение. Вместо этого используйте ScopedLock, и RAII сделает работу автоматически и безопасно во всех случаях:

void ShotSimulationService::SimulateShot(Shot shot) {
        Mutex::ScopedLock lock(MutexThreadLock);
        shots.insert(ShotsSetType::ValueType(SimulationShot(shot)));
        errorCount = 0;
        // unlock will be called by ScopedLock destructor
    }
Другие вопросы по тегам