新的boost :: thread导致对象析构函数被调用的次数超过预期?

时间:2017-05-21 14:10:53

标签: c++ multithreading boost destructor

下面发布的代码中的奇怪行为导致对象析构函数被多次调用。虽然代码没有因此而崩溃,但我只想找出这种行为发生的原因。这是一个非常简单的正常程序模板,很可能是Boost所有人都使用过的,但直到现在我才注意到这种行为。

#include <boost/thread.hpp>
#include <iostream>

class object
{
    private:

        int value;

    public:

    object();
    ~object();
    void pass( int value);
};

object::object()
{
    std::cout<<"constructing object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
object::~object()
{
    std::cout<<"destructing  object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
void object::pass( int value)
{
    this->object::value = value;
    std::cout<<"value passed is: "<<this->object::value<<std::endl;
}

class threaded
{
    private:

         object A;

    public:

    threaded();
    ~threaded();
    void init( int value);
};
threaded::threaded(){}
threaded::~threaded(){}
void threaded::init( int value)
{
    this->threaded::A.pass( value);
}

int main()
{
    threaded T;
    int unlucky_number = 13;

    boost::thread_group tg;

    tg.add_thread( new boost::thread( boost::bind( &threaded::init, T, unlucky_number)));

    tg.join_all();

    return 0;
}

这是代码输出。

constructing object: 0x7ffcb53157f0 with value: 0

destructing  object: 0x7ffcb53156d0 with value: 0 <----From here?
destructing  object: 0x7ffcb5315720 with value: 0
destructing  object: 0x7ffcb53157a0 with value: 0
destructing  object: 0x7ffcb5315780 with value: 0
destructing  object: 0x7ffcb5315710 with value: 0
destructing  object: 0x7ffcb53157c0 with value: 0
destructing  object: 0x7ffcb5315820 with value: 0
destructing  object: 0x7ffcb5315800 with value: 0 <----To here?

value passed is: 13
destructing  object: 0x1a5f2d8 with value: 13
destructing  object: 0x7ffcb53157f0 with value: 0

在第一个构造之后和行 value passed is: 13 之前销毁的对象必须以某种方式由boost线程库中的复制构造函数创建,但为什么它们从未构造,为什么没撞车?再加上他们的价值总是零,所以这不是垃圾记忆......任何想法?

所以应G.M.的要求我尝试创建复制构造函数只是为了在error_code.hpp中获得与boost相关的错误。

这是新代码加上编译它的错误。

#include <boost/thread.hpp>
#include <iostream>

class object
{
    private:

        int value;

    public:

    object();
    object( object const &copy_this);
    ~object();
    void pass( int value);
};

object::object()
{
    std::cout<<"constructing object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
object::object( object const &copy_this)
{
    std::cout<<"object copy constructor. "<<std::endl;
    this->object::value = copy_this.value;
}
object::~object()
{
    std::cout<<"destructing  object: "<<this<<" with value: "<<this->object::value<<std::endl;
}
void object::pass( int value)
{
    this->object::value = value;
    std::cout<<"value passed is: "<<this->object::value<<std::endl;
}

class threaded
{
    private:

         object A;

    public:

    threaded();
    threaded( threaded const &copy_this);
    ~threaded();
    void init( int value);
};
threaded::threaded(){}
threaded::threaded( threaded const &copy_this)
{
    std::cout<<"threaded copy constructor. "<<std::endl;
    this->threaded::A = copy_this.A;
}
threaded::~threaded(){}
void threaded::init( int value)
{
    this->threaded::A.pass( value);
}

int main()
{
    threaded T;
    int unlucky_number = 13;

    boost::thread_group tg;

    tg.add_thread( new boost::thread( boost::bind( &threaded::init, T, unlucky_number)));

    tg.join_all();
    //T.init(13);

    return 0;
}

||=== Build: Debug in boost_thread_destructor_problem (compiler: GNU GCC Compiler) ===|
obj/Debug/boost_thread_destructor_problem.o||In function `__static_initialization_and_destruction_0(int, int)':|
/usr/include/boost/system/error_code.hpp|221|undefined reference to `boost::system::generic_category()'|
/usr/include/boost/system/error_code.hpp|222|undefined reference to `boost::system::generic_category()'|
/usr/include/boost/system/error_code.hpp|223|undefined reference to `boost::system::system_category()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread_exception::thread_exception(int, char const*)':|
/usr/include/boost/thread/exceptions.hpp|51|undefined reference to `boost::system::system_category()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::condition_error::condition_error(int, char const*)':|
/usr/include/boost/thread/exceptions.hpp|84|undefined reference to `boost::system::system_category()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::thread_data_base::thread_data_base()':|
/usr/include/boost/thread/pthread/thread_data.hpp|152|undefined reference to `vtable for boost::detail::thread_data_base'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::interruption_checker::interruption_checker(pthread_mutex_t*, pthread_cond_t*)':|
/usr/include/boost/thread/pthread/thread_data.hpp|195|undefined reference to `boost::detail::get_current_thread_data()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::start_thread()':|
/usr/include/boost/thread/detail/thread.hpp|179|undefined reference to `boost::thread::start_thread_noexcept()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::~thread()':|
/usr/include/boost/thread/detail/thread.hpp|254|undefined reference to `boost::thread::detach()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::get_id() const':|
/usr/include/boost/thread/detail/thread.hpp|741|undefined reference to `boost::thread::native_handle()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread::join()':|
/usr/include/boost/thread/detail/thread.hpp|767|undefined reference to `boost::thread::join_noexcept()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::condition_variable::wait(boost::unique_lock<boost::mutex>&)':|
/usr/include/boost/thread/pthread/condition_variable.hpp|84|undefined reference to `boost::this_thread::interruption_point()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::shared_mutex::lock_shared()':|
/usr/include/boost/thread/pthread/shared_mutex.hpp|186|undefined reference to `boost::this_thread::disable_interruption::disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|186|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|186|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::shared_mutex::lock()':|
/usr/include/boost/thread/pthread/shared_mutex.hpp|287|undefined reference to `boost::this_thread::disable_interruption::disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|287|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
/usr/include/boost/thread/pthread/shared_mutex.hpp|287|undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::thread_group::join_all()':|
/usr/include/boost/thread/detail/thread_group.hpp|117|undefined reference to `boost::thread::joinable() const'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf1<void, threaded, int>, boost::_bi::list2<boost::_bi::value<threaded>, boost::_bi::value<int> > > >::thread_data(boost::_bi::bind_t<void, boost::_mfi::mf1<void, threaded, int>, boost::_bi::list2<boost::_bi::value<threaded>, boost::_bi::value<int> > >)':|
/usr/include/boost/thread/detail/thread.hpp|109|undefined reference to `boost::detail::thread_data_base::~thread_data_base()'|
obj/Debug/boost_thread_destructor_problem.o||In function `boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf1<void, threaded, int>, boost::_bi::list2<boost::_bi::value<threaded>, boost::_bi::value<int> > > >::~thread_data()':|
/usr/include/boost/thread/detail/thread.hpp|90|undefined reference to `boost::detail::thread_data_base::~thread_data_base()'|
/usr/include/boost/thread/detail/thread.hpp|90|undefined reference to `boost::detail::thread_data_base::~thread_data_base()'|
obj/Debug/boost_thread_destructor_problem.o:(.rodata._ZTIN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf1Iv8threadediEENS2_5list2INS2_5valueIS6_EENS9_IiEEEEEEEE[_ZTIN5boost6detail11thread_dataINS_3_bi6bind_tIvNS_4_mfi3mf1Iv8threadediEENS2_5list2INS2_5valueIS6_EENS9_IiEEEEEEEE]+0x10)||undefined reference to `typeinfo for boost::detail::thread_data_base'|
||error: ld returned 1 exit status|
||=== Build failed: 24 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===|

2 个答案:

答案 0 :(得分:3)

您可以通过避免bind来缓解这一问题。 Lambdas解决了这个问题 - 通常更有效率:

C++11

tg.create_thread([=]() mutable { T.init(unlucky_number); });

在C ++ 14中can be a bit more advanced

tg.create_thread([T=std::move(T), unlucky_number = 13]() mutable { T.init(unlucky_number); });

如果object复制费用昂贵,请考虑让其移动感知,例如

object(object const&)       = default;
object(object&&)            = default;
object& operator=(object&&) = default;

确保编译器生成特殊成员,即使您添加了用户声明的(非平凡的)构造函数/析构函数成员。

答案 1 :(得分:2)

由于您调用boost::bind ...

的方式
tg.add_thread(new boost::thread(boost::bind(&threaded::init, T, unlucky_number)));

T将按值传递。这可能会导致T实施boost::bind执行T的任何数量的复制。

由于您知道tg.add_thread(new boost::thread(boost::bind(&threaded::init, boost::ref(T), unlucky_number))); 在这种情况下会比使用它的线程更长,您可以通过引用强制传递...

tg.add_thread(new boost::thread(boost::bind(&threaded::init, &T, unlucky_number)));

或传递指针......

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
    <Table>
        <Name/>
        <Location/>
        <Citation>
            <Title />
            <Abstract />
            <Description/>
        </Citation>
        <metadataDate/>
    </Table>
</metadata>