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
}