Блокирует ли std :: map свои узлы, чтобы другие процессы не могли их удалить?

У меня здесь серьезная проблема.
У меня есть две разные задачи (например, процесс), работающие на моем ПЛК X20 формы B&R доступ к одному одноэлементному объекту «VarList». Его цель — разрешить межпроцессное взаимодействие через указатели.

Задача A — создание объекта, который включает в себя std :: map, с использованием статического метода getInstance (). Там указатель, если этот объект назначен глобальной переменной ПЛК, чтобы разрешить доступ каждой задачи к этому конкретному объекту. Эта задача также проверяет каждый цикл задачи на предмет вставки переменной в эту карту. В этом случае он пытается удалить этот вставленный узел снова, просто для целей тестирования.

Задача B получает указатель объекта через метод getInstance и вставляет bool * в карту.

После этого Задача A пытается удалить его снова, и он падает с нарушением прав доступа. Я могу получить доступ к узлам и их значениям. Я могу изменить эти значения. Но удаление узла, созданного в другой задаче, приводит к сбою, и я хотел бы знать, почему!

ПЛК является однопоточным, поэтому не должно быть одновременного доступа к памяти.

Это проблема блокировки? Или это логическая проблема? Проблема STL? Проблема с нулевым указателем? Или, может быть, снова проблема конкретной реализации для библиотеки std поставщика plc? Любая помощь, связанная с нарушением доступа, приветствуется!

Вот фрагменты кода упомянутого объекта, я удалил все, что не связано с проблемой, просто чтобы получить подсказку. извините, скорее всего это не компилируется:

Компилятор: gcc 4.1.2

Задача А:

#include <VarListe.hpp>
VarListe::Ptr VLInstanz;

void _INIT VLErzeugerInit(void)
{
VLInstanz = VarListe::getInstance("VLErzeuger");
}

void _CYCLIC VLErzeugerCyclic(void)
{
VLInstanz->checkNewVars(); // Access Violation here
}

Задача Б:

#include <VarListe.hpp>
VarListe::Ptr vals;

bool setPtr = true;void _INIT VarListeTestInit(void)
{
}

// btn_VarTest is a Boolean plc Variable for a button on the Visu
void _CYCLIC VarListeTestCyclic(void)
{
try
{
if(btn_VarTest &&setPtr)
{
vals = VarListe::getInstance("VarListe1");
vals->setVar("btn_VarTest",&btn_VarTest);
//vals->checkNewVars(); // Works perfect if used here. Thats not the point
setPtr = false;
}
catch (...)
{
}
}

VarListe.hpp

#include <map>
#include <deque>
#include <string>
#include <boost/shared_ptr.hpp>

using namespace std;

class VarListe
{
public:

typedef bool*           BoolPtr;

typedef boost::shared_ptr<VarListe> Ptr;

static Ptr getInstance(string owner);
static Ptr _alwaysUseGetInstance;
static char owners[200];

void checkNewVars();

private:
typedef map<string, BoolPtr >           BoolPtrMap;

typedef deque<BoolPtrMap::iterator>     BoolVarQueue;
BoolVarQueue                            _boolVarQueue;

BoolPtrMap      _boolListe;

public:
void setVar(string key, bool* value);
};

VarListe.cpp

#include <VarListe.hpp>

VarListe::Ptr VarListe::_alwaysUseGetInstance; // Singleton static Variable; used olny by the object creator
char    VarListe::owners[200]; // just to test which task creats the object

#include <../../Temp/Includes/globalvar.h> // For the global PLC variable 'GlobalVarListe'

// This static Method runs perfectly, no need to check here
VarListe::Ptr VarListe::getInstance(string owner)
{

if(GlobalVarListe == 1337)
{
strcpy(VarListe::owners, "");
owner += "(Builder)";
if (!VarListe::_alwaysUseGetInstance)
VarListe::_alwaysUseGetInstance = VarListe::Ptr(new VarListe);
GlobalVarListe = (UDINT) &VarListe::_alwaysUseGetInstance;
VarListe::_alwaysUseGetInstance->setVar("VarListOwners",VarListe::owners);
}
VarListe::Ptr tempVL = *( (VarListe::Ptr*) GlobalVarListe);
VarListe::CharPtrPair locOwners;
if(tempVL->assertVar("VarListOwners",locOwners))
{
string temp = string(locOwners.first);
temp = temp + owner + " + ";
strcpy(locOwners.first, temp.c_str());
}

return tempVL;
}

// This Method is used in Task B
void VarListe::setVar(string key, bool* value)
{
pair<BoolPtrMap::iterator, bool > eingetragen;
eingetragen = _boolListe.insert(pair<string, BoolPtr>(key, value ));

if(eingetragen.second == false)
{
}
else
_boolVarQueue.push_back(eingetragen.first);
}

// This method is in Task A
void VarListe::checkNewVars()
{
if(!_boolVarQueue.empty())
{
string key = _boolVarQueue.front()->first;  //OK,
BoolPtr bp = _boolVarQueue.front()->second; //OK
_boolVarQueue.front()->second = 0;          //OK
_boolListe[key] = bp;                       //OK
BoolPtrMap::iterator fund = _boolListe.find(key); // OK
if (fund != this->_boolListe.end())         // OK
{
_boolListe.erase(key);                      //Access Violation: Code 9101 only if used by Task A
_boolListe.erase(_boolVarQueue.front());    //Access Violation: Code 9101
_boolListe.erase(fund);                     //Access Violation: Code 9101
}
_boolVarQueue.pop_front();                  //OK
_boolListe[key] = bp;                       //OK
}
}

Спасибо!

0

Решение

Размещение карты STL в любой совместной памяти между процессами (или задачами) с отдельными адресными пространствами невозможно сделать без изменений.

Проблема состоит в том, что, если процесс A вставляет данные в карту, он выделяет любую новую память из своего собственного адресного пространства (а карты действительно выделяют память для новых записей), что недоступно для процесса B. Итак, если процесс B тогда пытается получить доступ к этим недавно вставленным данным, очень вероятно, что получит ошибку (например, нарушение доступа).

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

2

Другие решения

Стандартная реализация не имеет / не требует никакой блокировки:

http://www.sgi.com/tech/stl/thread_safety.html

Разумеется, для реализации допустимо включать блокировки, если она того пожелает.

1

По вопросам рекламы [email protected]