2011-08-14 11 views
1

Linux上でC++を使用しているときに問題が発生しました。Linuxでのstd :: mapによるメモリアライメントの問題

私はこのようになりますベースメッセージクラスを持っている:ここでは

class Der1 : public MsgBase 
{ 
    public: 
     Der1(); 
     virtual ~Der1(); 

     // IEs 
     MSGIE_UINT32 ueId; 
     MSGIE_String configFileName; 
}; 

MSGIE_UINT32とMSGIE_StringしたがってMSGIEBaseから派生したクラスです:Der1はMsgBaseから派生してのように見えるさ

class MsgBase 
{ 
    public: 
     MsgBase(unsigned int msgid); 
     map < unsigned int, MSGIEBase* > messageIE_Map; // map for IEs 
     unsigned int messageId; // 32 bit message id 
}; 

クラスそれらのアドレスは上記の基底クラスで定義されたマップに格納することができます。 Der1が構築されると、ueIdとconfigFileNameのアドレスがマップに格納されます。 マップのサイズを印刷すると(gdbとプログラムで)、24となります。 [_M_header = 16、_M_node_count = 4、_M_key_compare = 1,3バイトのパディングです。

ここまではすべて問題ありません。 Der1オブジェクトポインタはイベントオブジェクトの中に入れられ、イベントはキューにポストされます。イベントクラスは次のようになります。

class Event 
{ 
    public: 
     MsgBase* msgPtr; 
}; 

異なるスレッドは、キューからイベントを削除するmsgPtrを抽出し、Der1ポインタにキャストして、問題が始まる場所です。

ここでプログラムのマップのサイズを印刷すると21になります。つまり、MsgBaseクラスの次のメンバーのアドレス、つまりmessageIdが3バイトずれるため、messageIdの値が完全に変更されます。 (gdbを通して見ると、アドレスはそのままで、マップのサイズも24です)。

これは私の知る限りでは、メモリアラインメントが異なる機能で一貫していないため、なぜクラスのメモリのアドレスが新しいクラスを使用して割り当てられたのか。私はLinux 2.6.27を使用しています。 、gccバージョン4.1.1 、RHEL-4。非仮想デストラクタ/コピー/割り当ての問題を除外するための

+2

これらのオブジェクトをどのように操作するかによって異なります。コードを表示する。 (私はメモリアライメントの問題だとは思わない) – BatchyX

+1

マップの大きさとメモリのアライメントについてのあなたの前提は、間違ったパスを取っていると思う。あなたは実際の問題を説明することは決してありません。私は関係のないと思う症状だけを説明します。あなたのキューからポップしたときに、あなたのプログラムで(間違って)どうなるでしょうか?私は、この時点でソースのプッシュとポップの部分がはるかに関連性があると思うだろう、私はそこに問題があると推測している。 – Joe

+0

実際に問題がありますか?関連するコードのいくつかを教えてください。 –

答えて

1

MsgBaseに以下を追加してくださいは:

public: 
    virtual ~MsgBase(); 
private: 
    MsgBase(MsgBase const& other); 
    MsgBase& operator=(MsgBase const& other); 
0

私はステップによって、すべての必要な情報のステップを提供しようとします:

情報1 :関連するコード。

//Step 1: Create msg and fill message Id 
MsgBase*msgPtr = new Der1(); 

// C'tor of Der1 is as follows: 
Der1::Der1() 
      : MsgBase (ATS_SUTD_EPCTESTER_ATTACH_SCENARIO_MsgId), // msgid is 13(0xd) 
      ueId (IE_UE_KEY, "UE", false), 
      configFileName (IE_CONFIG_FILE_NAME_KEY, "Configuration File Name", false) 
{ 
      // Insert the IEs in the map 
this->addIEEntry (IE_UE_KEY, &ueId); // this puts entries in the map 
this->addIEEntry (IE_CONFIG_FILE_NAME_KEY, &configFileName); 
} 

// Step 2: Declare event and post the event 
Event* event = new Event (eventId, "Event"); 
event->setData(msgPtr, hdr); 

// check the message id at this stage ( 
cout << "msgId = " << (((Der1*)msgPtr)->messageId)<< endl; // Here it comes out 
                  // to be 0xd which is correct 

// post the event 
AppClass::getInstance()->addEventAndSchedule (event); 

//The queue is a member of AppClass and has been defined as 
std::list <EventBase* > eventQueue; 

// The code which inserts data into the queue is as follows: 
bool AppClass::addEventAndSchedule (EventBase* ev) 
{ 
    if (ev == NULL) return false; 
    this->eventQueueMutex.acquireLock(); 
    this->eventQueue.push_back(ev); 
    this->eventQueueMutex.releaseLock(); 

    // Submit Job to Scheduler 
    bool status = JobScheduler::getInstance()->scheduleJob(this); 
    return status; 
} 

// The event class is 
class Event: public EventBase 
{ 
    public: 
    Event(); 
    virtual ~Event(); 
    Event (int evId); 
    Event (int evId, string evName); 
    MsgBase* getMessagePtr(); 
    void setData (MsgBase* mPtr, Header* hPtr) 

    private: 
    // Prevent copying 
    Event& operator= (Event& ev); 
    Event (Event& evBase); 

    MsgBase* msgPtr; 
    Header* hdrPtr; 
}; 

void Event::setData (MsgBase* mPtr, Header* hPtr) 
{ 
    this->msgPtr = mPtr; 
    this->hdrPtr = hPtr; 
} 


Step 3 : Extract the event and re-print the message Id 
// The code which extracts data from the queue is as follows: 
void AppClass::process() 
{ 
       EventBase* beventPtr = NULL; 
       this->eventQueueMutex.acquireLock(); 

    if (!this->eventQueue.empty()) 
    { 
     beventPtr = (EventBase*)(this->eventQueue.front()); 
     this->eventQueue.pop_front(); 
    } 
    else 
    { 
     isQueueEmpty = true; 
    } 

    this->eventQueueMutex.releaseLock(); 
    Event* eventPtr = (Event*)beventPtr ; 

          Der1* msgPtr = (Der1*)(eventPtr->getMessagePtr()) ; 
    cout << "msgId = " << msgPtr->messageId << endl; // This value 
      //comes out to be incorrect it is now 0xd000000 i.e. a 3 byte shift 

} 

情報2:正確な問題。 正確な問題は、 'messasgeId'が移行時に変更されていることです。最初は0xdですが、キューからポップした後は0xd000000になります。このため、すべての処理が停止します。このパラメータのアドレスは、プログラムで印刷されたときに0x82bd7ccから0x82bd7c9に変更されます。しかし、gdbから見るとまだ0x82bd7ccであり、値はまだ0xdです。

情報3:コンパイラフラグ。 コンパイラのフラグはすべてのファイルで同じです。 -O0 -g3 -Wall -fmessage-length = 0