Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 跨线程复制boost::异常崩溃_C++_Boost - Fatal编程技术网

C++ 跨线程复制boost::异常崩溃

C++ 跨线程复制boost::异常崩溃,c++,boost,C++,Boost,下面是将boost::exception对象从一个线程复制/传输到另一个线程的示例代码,在销毁exception/exception_ptr内部状态期间由于争用条件而崩溃。我不确定解决这个问题的最佳方法是什么 使用的boost版本是1.42,平台是运行在双核Intel m/c上的Ubuntu lucid。编译器是GCC4.4.3 #include <iostream> #include <boost/exception/all.hpp> #include <boo

下面是将boost::exception对象从一个线程复制/传输到另一个线程的示例代码,在销毁exception/exception_ptr内部状态期间由于争用条件而崩溃。我不确定解决这个问题的最佳方法是什么

使用的boost版本是1.42,平台是运行在双核Intel m/c上的Ubuntu lucid。编译器是GCC4.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 
*/
#包括
#包括
#包括
结构异常
:公共虚拟std::异常
,公共虚拟boost::异常
{
};
结构MyException:公共虚拟异常{};
结构MyTag{};
typedef boost::error\u info MyError;
结构测试
{
测试()
{
_t、 重置(新的boost::thread(boost::bind(&Test::executor,this));
}
~Test()
{
_t->join();
}
无效执行人()
{
std::cerr set_异常(boost::copy_异常(MyException()pm(new boost::promise());
boost::unique_future fu=pm->get_future();
{
boost::unique_lock lk(_mx);
_q、 推回(pm);
pm.reset();
}
_cv.通知_one();
fu.get();
断言(假);
}
捕获(常量MyException&e)
{
投掷;
}
捕获(常量boost::异常&)
{
断言(假);
}
捕获(…)
{
断言(假);
}
}
无效运行()
{
标准:cerr>\u q;
boost::共享\u ptr\t;
boost::条件变量任意cv;
};
int main()
{
试验;
test.run();
}
/*
#0 0x080526bd在boost::exception_detail::refcount_ptr::release(this=0x806e26c)中位于/boost_1_42_0/boost/exception/exception.hpp:79
#在/boost_1_42_0/boost/exception/exception/exception处,1 0x0804f7c5英寸~refcount_ptr(这=0x806e26c,英寸=chrg)。hpp:34
#在/boost\u 1\u 42\u 0/boost/exception/exception处有2个0x0804bb61 in~exception(这个=0x806e268,\u in\u chrg=)hpp:254
#3 0x0805579a位于/boost\u 1\u 42\u 0/boost/exception/exception.hpp:391处的克隆执行(this=0x806e260,\uu在\u chrg=,\uu vtt\u parm=)中
#来自/usr/lib/libstdc++.so.6的4 0x001ff633英寸()
#5 0x0027233d位于/lib/libgcc_.so.1的_Unwind_DeleteException()中
#6 0x001fe110位于/usr/lib/libstdc++.so.6中的uu cxa_end_catch()中
#测试中的7 0x0804f7a4::在ex_org.cpp:89处运行(this=0xbfff74c)
#8 0x0804b869在exu org.cpp:106的main()中
*/

我不是boost专家,但我注意到一些竞争问题,它在调试模式下运行正常吗

对于遗嘱执行人,我会这样写

void executor()
{
    std::cerr << "executor: starting ...\n";

    for (;;)
    {            
        _cv.wait(lk);

        boost::unique_lock<boost::mutex> lk(_mx);

        __sync_synchronize (); // Tells the compiler to prevent optimizations

        if ( !_q.empty() ) {                
            boost::shared_ptr<boost::promise<int> > pt = _q.front();
            _q.pop_front();
            pt->set_exception(boost::copy_exception(MyException() << MyError("test")));
        }
    }
}
void executor()
{
std::cerr set_异常(boost::copy_异常(MyException()pm(new boost::promise());
boost::unique_future fu=pm->get_future();
{
boost::unique_lock lk(_mx);
//防止编译器混合上面和下面的代码
__sync_synchronize();
_q、 推回(pm);
pm.reset();
}
_cv.通知_one();
//这一个是偏执狂的一个;),你必须检查没有!
__sync_synchronize();
{
//由于fu必须持有一份目前正在进行的内部参考pm
//被另一个线程更改!
boost::unique_lock lk(_mx);
//那么你就可以确信,在这一点上,一切都是连贯的
//保存异常内容的堆栈帧不会损坏
fu.get();
}
断言(假);
}

捕获非引用而不是引用如何?这样就可以创建本地副本。没有帮助,仍然会导致相同的崩溃。尝试使用g++4.7.0和boost 1.49再现此情况,但您的示例在那里运行得非常好(在英特尔i5上的Arch Linux 3.4.0下)我不确定boost 1.42和1.49之间是否有任何改变,这可能解决了问题,但核心堆栈跟踪表明存在竞争条件(refcount_ptr destructor),因此它可能会在一段时间内运行良好。对我来说,它也可以正常运行约1-2分钟(通常)然后最终导致seg故障。我已经运行了5个程序实例40分钟了,但没有一个崩溃。要么我非常幸运,要么它在升级到新版本的过程中被修复了
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);

            // prevent the compiler from mixing above and below code
            __sync_synchronize ();

            _q.push_back(pm);
            pm.reset();
        }

        _cv.notify_one();

        // This one is the paranoïd's one ;), one must check without ! 
        __sync_synchronize ();

        {
            // since fu must holds an internal reference pm being currently 
            // changed by the other thread !
            boost::unique_lock<boost::mutex> lk(_mx);

            // Then you are assured that everything is coherent at this point
            // the stack frame holding the exception stuffs won't be corrupted

            fu.get();
        }

        assert(false);
    }