2016-03-22 16 views
3

QNXでコードが定期的にクラッシュしています。 std::call_onceを使用して初期化怠惰である0x85dd6acオブジェクトのSTD ::マップのメンバ変数にアクセスしようとしているときにアドレス0x85dd6acでメモリにアクセスすることはできません)std :: call_once QNXの遅延初期化問題

:それは変数を読み込みエラー

エラーでクラッシュします。 get()によって返されたオブジェクトは、プロセスがクラッシュしているアクセスされたいくつかの点で

mutable std::aligned_storage<sizeof(A), alignof(A) >::type m_value; 

void init(A *ptr) 
{ 
    new (ptr) A(); 
} 

inline T* data() const 
{ 
    return reinterpret_cast<A*>(&m_value); 
} 

const A& get() const 
{ 
    std::call_once(m_once_flag, init, data()); 
    return *data(); 
} 

は、初期化は、次の擬似コードを用いて行われます。

他のプラットフォームでは、問題は再現されず、デバッグするのが非常に困難です。 コードから、オブジェクトが初期化されず、その時点で削除できないことがわかります。

std::call_onceの実装では、スレッドの安全性またはメモリの順序付けで問題が発生する可能性があります。 誰かがQNXプラットフォームのstd :: call_onceやそのようなバグの経験がありますか? 問題をどのように見つけることができますか?

+0

GCCを使用していますか?野生の推測:QNX Pthreadsの実装では、静的オブジェクトに対してPTHREAD_ONCE_INITを使用することのみがサポートされており、 'std :: once_flag'タイプのデータメンバーの使用は機能しません。 'm_once_flag'の代わりにグローバルな' std :: once_flag'を使うと違いがありますか? (これは、オブジェクトごとに一度ではなく、一度だけinitを実行できることを意味していますが、問題を追跡するのに役立ちます)。 –

+0

@Jonathan、それは 'mutable'なので、非静的なデータメンバでなければなりません(接頭辞「m_」は強く示唆しています) –

+0

なぜ、格納する必要があるときだけ変数をマップに格納しないのですか?私はそれを取得しません –

答えて

1

私はQNXでstd :: call_onceを使用することで同じ経験をしましたが、クラッシュの横にマルチスレッドアプリケーションでデッドロックが発生する可能性があります。私はSTDを交換するには、次のパターンを使用することをお勧め::なcall_once:

static std::atomic<bool> once_flag = false; 
if (!once_flag.exchange(true)) 
{ 
    // This part will be executed only once. 
    // ... 
} 

UPDATE FEFEのコメントに基づいて、このソリューションは、受動的な実行のブロックの条件を満たしていない(http://www.cplusplus.com/reference/mutex/call_once/の詳細を参照してください)。

これも同様にする必要がある場合は、より複雑なソリューションを実装する必要があります。ここに例があります:

static std::atomic<bool> once_flag = false; 
static std::atomic<bool> once_call_done = false; 
if (!once_flag.exchange(true)) 
{ 
    // This part will be executed only once. 
    // ... 

    once_call_done = true; 
} 
else 
{ 
    // Block until the call once part is running. 
    while(!once_call_done) 
    { 
     sleep(1); 
    } 
} 
+1

問題は、このブロックに続くコードは、初期化の実行が終了する前に実行される可能性があります。初期化が完了する前にフラグが変更されるので、他のスレッドは、初期化が完了する前に 'one_flag'が' true'であると見つけることができる。 – fefe

+0

ありがとう、良い点。私はあなたのコメントに基づいて私の答えを変更します。 –

1

問題はstd :: call_onceで発生しました。実装上のバグです。 一時的にmutexに置き換えて問題を解決しました。 詳細を詳しく調べる時間がありませんでしたが、この情報が似たような問題を持つ人に役立つことを願っています。

あなたのコメントはありがとうございます。