【问题标题】:LinearHashTable iter not dereferencable and iter notLinearHashTable iter 不可取消引用且 iter 不可
【发布时间】:2015-01-09 00:11:06
【问题描述】:

大家好:)

我在我的 VC++ 项目(Microsoft Visual C++ Compiler 18.00.21005.1 for x86 platform)中使用 1.5.4-all (2014-10-22)。

我的问题是一段时间后我收到以下错误消息。发生错误的时间差别很大 - 有时会在 30 秒后发生,有时会在 5 分钟后发生。

我可以在 LinearHashTable.h 文件的第 214 行找到错误的来源:

我有以下方法将镜头(结构)添加到表中:

    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());
        }
    }

Update 方法经常被安静地调用 - 总是在新的网络摄像头框架可用时调用。

错误的调用栈从下面一行开始:

    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;
        }

有人知道为什么会出现这个问题吗?

欢迎任何帮助和任何反馈!我完全不知道这里出了什么问题:(

谢谢!

【问题讨论】:

  • 迭代时不要锁定互斥锁,以便在迭代时插入其他线程。这可能会使现有的迭代器失效,甚至在循环中。不确定这是否是问题,但值得研究。

标签: c++ visual-c++ poco-libraries


【解决方案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
    }

【讨论】:

    猜你喜欢
    • 2019-03-19
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    相关资源
    最近更新 更多