4

以下のサンプル コードは、boost::exception オブジェクトを 1 つのスレッドから別のスレッドにコピー/転送し、例外/exception_ptr 内部状態の破棄中の競合状態によりクラッシュします。それを解決する最善の方法が何であるかはわかりません。

使用したブースト バージョンは 1.42 で、プラットフォームはデュアル コア Intel m/c で実行される Ubuntu lucid です。コンパイラは gcc 4.4.3 でした。

#include <iostream>

#include <boost/exception/all.hpp>
#include <boost/thread.hpp>

struct Exception
    : public virtual std::exception
    , public virtual boost::exception
{
};

struct MyException : public virtual Exception {};

struct MyTag {};

typedef boost::error_info<MyTag, std::string> MyError;

struct Test
{
    Test()
    {
        _t.reset(new boost::thread(boost::bind(&Test::executor, this)));
    }

    ~Test()
    {
        _t->join();
    }

    void executor()
    {
        std::cerr << "executor: starting ...\n";
        for (;;)
        {
            boost::unique_lock<boost::mutex> lk(_mx);
            while(_q.empty())
            {
                _cv.wait(lk);
            }
            {
                boost::shared_ptr<boost::promise<int> > pt = _q.front();
                _q.pop_front();
                lk.unlock();
                pt->set_exception(boost::copy_exception(MyException() << MyError("test")));
            }
        }
    }

    void run_impl()
    {
        try
        {
            boost::shared_ptr< boost::promise<int> > pm(new boost::promise<int>());

            boost::unique_future<int> fu = pm->get_future();
            {
                boost::unique_lock<boost::mutex> lk(_mx);
                _q.push_back(pm);
                pm.reset();
            }
            _cv.notify_one();

            fu.get();
            assert(false);
        }
        catch (const MyException& e)
        {
            throw;
        }
        catch (const boost::exception& )
        {
            assert(false);
        }
        catch (...)
        {
            assert(false);
        }
    }

    void run()
    {
        std::cerr << "run: starting ...\n";
        for (;;)
        {
            try
            {
                run_impl();
            }
            catch (...)
            {
            }
        }
    }

private:

    boost::mutex _mx;
    std::list< boost::shared_ptr< boost::promise<int> > > _q;
    boost::shared_ptr<boost::thread> _t;
    boost::condition_variable_any _cv;
};

int main()
{
    Test test;
    test.run();
}

/*
#0  0x080526bd in boost::exception_detail::refcount_ptr<boost::exception_detail::error_info_container>::release (this=0x806e26c) at /boost_1_42_0/boost/exception/exception.hpp:79            
#1  0x0804f7c5 in ~refcount_ptr (this=0x806e26c, __in_chrg=<value optimized out>) at /boost_1_42_0/boost/exception/exception.hpp:34                                                           
#2  0x0804bb61 in ~exception (this=0x806e268, __in_chrg=<value optimized out>) at /boost_1_42_0/boost/exception/exception.hpp:254                                                             
#3  0x0805579a in ~clone_impl (this=0x806e260, __in_chrg=<value optimized out>, __vtt_parm=<value optimized out>) at /boost_1_42_0/boost/exception/exception.hpp:391                          
#4  0x001ff633 in ?? () from /usr/lib/libstdc++.so.6                                                                                                                                                           
#5  0x0027233d in _Unwind_DeleteException () from /lib/libgcc_s.so.1                                                                                                                                           
#6  0x001fe110 in __cxa_end_catch () from /usr/lib/libstdc++.so.6                                                                                                                                              
#7  0x0804f7a4 in Test::run (this=0xbffff74c) at ex_org.cpp:89                                                                                                                                                 
#8  0x0804b869 in main () at ex_org.cpp:106 
*/
4

1 に答える 1