ここで重大な問題が発生しました。1 つのシングルトン オブジェクト「VarList」にアクセスする 2 つの異なるタスク (プロセスなど) が PLC X20 フォーム B&R で実行されています。その目的は、ポインターを介したプロセス間通信を可能にすることです。
タスク A は、静的な getInstance() メソッドを使用して std::map を含むオブジェクトを作成しています。そのオブジェクトがグローバル PLC 変数に割り当てられている場合は、すべてのタスクからその特定のオブジェクトへのアクセスを許可するポインタがあります。そのタスクは、そのマップへの変数の挿入について、すべてのタスク サイクルもチェックしています。その場合、テスト目的で、挿入されたノードを再度削除しようとします。
タスク B は、getInstance メソッドを介してオブジェクトのポインターを取得し、bool* をマップに挿入します。
その後、タスク A が再度削除しようとすると、アクセス違反でクラッシュします。ノードとその値にアクセスできます。私はその価値観を変えることができます。しかし、別のタスクで作成されたノードを消去するとクラッシュするので、その理由を知りたいです!
PLC はシングルスレッドであるため、メモリへの同時アクセスはありません。
これはロックの問題ですか?それともこれはロジックの問題ですか?STLの問題?Null ポインタの問題? それとも、plc ベンダーの std ライブラリの特定の実装の問題でしょうか? アクセス違反に関連するヘルプは大歓迎です!
上記のオブジェクトのコード スニペットを次に示します。ヒントを得るために、問題に関係のないものはすべて削除しました。申し訳ありませんが、コンパイルできない可能性が最も高いです:
コンパイラ: gcc 4.1.2
タスク A:
#include <VarListe.hpp>
VarListe::Ptr VLInstanz;
void _INIT VLErzeugerInit(void)
{
VLInstanz = VarListe::getInstance("VLErzeuger");
}
void _CYCLIC VLErzeugerCyclic(void)
{
VLInstanz->checkNewVars(); // Access Violation here
}
タスク B:
#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
}
}