3

デフォルトの最適化設定 (/O2) で VS2012 を使用していますが、この問題はリリース モードでのみ存在します。

michael_deque(標準 GC を使用した) および (抽象) type へのポインターを使用するコードがいくつかありますT
から派生した型へのポインターをプッシュバックしようとすると、 の関数Tを終了するときにアプリケーションがクラッシュします。push_back()michael_deque

問題はこの特定の type に正確に依存しているようですT。なぜなら、ダミーの class を作成し、fooそれをクラスで派生させbar(そしてコンストラクターで何かを出力して最適化されないようにする)、そしてnew bar()michael_deque にプッシュバックしてもクラッシュしないからです。

問題のクラスTは次のとおりです。

class Task
{
public:
    Task() : started(false), unfinishedTasks(1), taskID(++taskIDCounter) {};
    Task(unsigned int parentID_) : started(false), unfinishedTasks(1), taskID(++taskIDCounter), parentID(parentID_)/*, taken(0)*/ {};
    virtual ~Task() = 0 {};

    virtual void execute() final
    {
        this->doActualWork();
        unfinishedTasks--;
    }

    virtual void doActualWork() = 0;
public:
    unsigned int taskID;    //ID of this task
    unsigned int parentID;  //ID of the parent of this task
    bool started;
    std::atomic<unsigned int> unfinishedTasks; //Number of child tasks that are still unfinished
    std::vector<unsigned int> dependencies; //list of IDs of all tasks that this task depends on

};

エラーは最小限のプログラムで再現できます (私と同じ方法でこれを実行できる環境がある場合はstd::atomic<unsigned int> taskIDCounter、Task クラスがそれを見ることができる場所に置くだけです):

#include <cds/container/michael_deque.h>
#include "task.hpp"
class a : public Task
{
a()
    {
        std::cout<<"dummy print"<<std::endl;
    }
    virtual ~a()
    {
    }

    virtual void doActualWork()
    {
        std::cout<<"whatever"<<std::endl;
    }
};



int main()
{
    cds::Initialize();

    {
        cds::gc::HP hpGC;
        cds::gc::HP::thread_gc myThreadGC;

        cds::container::MichaelDeque<cds::gc::HP,Task*> tasks;
        tasks.push_back(new a()); //will crash at the end of push_back
    }
        cds::Terminate();
}

これの原因は何ですか?最適化問題で問題を引き起こすクラス Task で未定義のことをしますか?

4

1 に答える 1

5

それは確かにコンパイラのバグでした。具体的には、Visual Studio 2012 のアトミック実装に関連するバグでした。

std::atomic クラスの一部のテンプレートの特殊化は、スタック フレーム ポインター (ebp) を、変更の前後にバックアップしたり、スタックからポップしたりせずに変更します。libcds ライブラリはこれらの特殊化の 1 つを使用しており、結果として不正なフレーム ポインターが原因で、関数のスコープ外で実行すると、不正なメモリ アクセスが発生することがあります (未定義の動作により、デバッグ モードでの壊滅的な障害が防止されているようです)。

この特殊なケースの修正は、libcds が Visual Studio によって提供される標準のアトミック ライブラリとは異なるアトミック ライブラリを使用するようにすることでした。ライブラリは、cxx11_atomic.h で使用する実装を決定します。

#if defined(CDS_USE_BOOST_ATOMIC)
#   error "Boost.atomic is not supported"
//#   include <boost/version.hpp>
//#   if BOOST_VERSION >= 105300
//#       include <boost/atomic.hpp>
//#       define CDS_ATOMIC boost
//#       define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
//#       define CDS_CXX11_ATOMIC_END_NAMESPACE }
//#   else
//#       error "Boost version 1.53 or above is needed for boost.atomic"
//#   endif

#elif CDS_CXX11_ATOMIC_SUPPORT == 1
    // Compiler supports C++11 atomic (conditionally defined in cds/details/defs.h)
#   include <cds/compiler/cxx11_atomic_prepatches.h>
#   include <atomic>
#   define CDS_ATOMIC std
#   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
#   define CDS_CXX11_ATOMIC_END_NAMESPACE }
#   include <cds/compiler/cxx11_atomic_patches.h>
#else
#   include <cds/compiler/cxx11_atomic.h>
#   define CDS_ATOMIC cds::cxx11_atomics
#   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomics {
#   define CDS_CXX11_ATOMIC_END_NAMESPACE }}
#endif

if ステートメントの 2 番目のブランチは、次のように変更できます。

#elif CDS_CXX11_ATOMIC_SUPPORT == 255

これにより、ライブラリは常に独自のアトミック実装を使用するようになります。

于 2013-09-01T10:13:43.370 に答える