Hi,
I have a small example program that crashes from time to time.
I would appreciate some help to understand why.
In function run() executed on the main thread I create a
packaged_task (pt), put it in a queue (_q) and wait for it to get executed (fu.get()).
In another thread the tasks are executed when the queue _q is populated.
The task I'm running always throws/rethrows intentionally.
It results (from time to time) in an access violation when the unique_future, fu, is deleted.
See the stack trace at the bottom.
Anybody see any flaws in this design?
I have tried 1.47.0 and 1.48.0, MSVC 2005.
Here's the code.
*****************************************************
#include
<boost/exception/all.hpp>
#include
<boost/thread.hpp>
#include
<sstream>
#include
<iostream>
struct Exception
:
public virtual std::exception
,
public virtual boost::exception
{
};
struct TheException :
public virtual Exception {};
void throwf()
{
try
{
BOOST_THROW_EXCEPTION(TheException());
}
catch (...)
{
boost::current_exception_diagnostic_information();
throw;
}
}
struct Test
{
Test()
{
_t.reset(new boost::thread(boost::bind(&Test::executor,
this)));
}
~Test()
{
_t->join();
}
void executor()
{
for (;;)
{
boost::unique_lock<boost::mutex> lk(_mx);
while(_q.empty())
{
_cv.wait(lk);
}
boost::shared_ptr< boost::packaged_task<void> > pt = _q.front();
_q.pop_front();
lk.unlock();
(*pt)();
}
}
void run()
{
for (;;)
{
const int N = 20000;
for (int j = 0; j < N; ++j)
{
boost::shared_ptr< boost::packaged_task<void> > pt(new boost::packaged_task<void>(throwf));
boost::unique_future<void> fu = pt->get_future();
{
boost::unique_lock<boost::mutex> lk(_mx);
_q.push_back(pt);
pt.reset();
}
_cv.notify_one();
try
{
fu.get();
assert(false);
}
catch (const TheException& )
{
}
catch (const boost::exception& )
{
assert(false);
}
catch (...) {
assert(false);
}
}
std::cout <<
".";
}
}
private:
boost::mutex _mx;
std::list< boost::shared_ptr< boost::packaged_task<void> > > _q;
boost::shared_ptr<boost::thread> _t;
boost::condition_variable_any _cv;
};
int main(int,
char*)
{
Test test;
test.run();
}
*****************************************************
Here is the callstack, program terminated with access violation.
Unhandled exception at 0x0043196b in crasher.exe: 0xC0000005: Access violation reading location 0xdddddded.
> crasher.exe!boost::exception_detail::refcount_ptr<boost::exception_detail::error_info_container>::release() Line 78 + 0x18 bytes
C++
crasher.exe!boost::exception_detail::refcount_ptr<boost::exception_detail::error_info_container>::~refcount_ptr<boost::exception_detail::error_info_container>()
Line 35 C++
crasher.exe!boost::exception::~exception() Line 278 + 0xb bytes C++
crasher.exe!boost::exception_detail::clone_impl<TheException>::`vbase destructor'() + 0x41 bytes C++
crasher.exe!boost::exception_detail::clone_impl<TheException>::`scalar deleting destructor'() + 0x2b bytes C++
crasher.exe!boost::checked_delete<boost::exception_detail::clone_base const >(const boost::exception_detail::clone_base * x=0x006f7d10)
Line 34 + 0x35 bytes C++
crasher.exe!boost::detail::sp_counted_impl_p<boost::exception_detail::clone_base const >::dispose() Line 78 + 0xc bytes
C++
crasher.exe!boost::detail::sp_counted_base::release() Line 102 + 0xf bytes C++
crasher.exe!boost::detail::shared_count::~shared_count() Line 309 C++
crasher.exe!boost::shared_ptr<boost::exception_detail::clone_base const >::~shared_ptr<boost::exception_detail::clone_base const
>() + 0x2e bytes C++
crasher.exe!boost::exception_ptr::~exception_ptr() + 0x2b bytes C++
crasher.exe!boost::detail::future_object_base::~future_object_base() Line 106 + 0x9c bytes C++
crasher.exe!boost::detail::future_object<void>::~future_object<void>() + 0x2b bytes C++
crasher.exe!boost::detail::task_base<void>::~task_base<void>() + 0x2b bytes C++
crasher.exe!boost::detail::task_object<void,void (__cdecl*)(void)>::~task_object<void,void (__cdecl*)(void)>() + 0x2b bytes
C++
crasher.exe!boost::detail::task_object<void,void (__cdecl*)(void)>::`scalar deleting destructor'() + 0x2b bytes
C++
crasher.exe!boost::checked_delete<boost::detail::task_object<void,void (__cdecl*)(void)> >(boost::detail::task_object<void,void
(__cdecl*)(void)> * x=0x006f7b10) Line 34 + 0x34 bytes C++
crasher.exe!boost::detail::sp_counted_impl_p<boost::detail::task_object<void,void (__cdecl*)(void)> >::dispose() Line 78 + 0xc
bytes C++
crasher.exe!boost::detail::sp_counted_base::release() Line 102 + 0xf bytes C++
crasher.exe!boost::detail::shared_count::~shared_count() Line 309 C++
crasher.exe!boost::shared_ptr<boost::detail::future_object<void> >::~shared_ptr<boost::detail::future_object<void> >() + 0x2e
bytes C++
crasher.exe!boost::unique_future<void>::~unique_future<void>() Line 644 + 0x2b bytes C++
crasher.exe!Test::run() Line 95 + 0xc bytes C++
crasher.exe!main(int __formal=1, int __formal=1) Line 112 C++
crasher.exe!__tmainCRTStartup() Line 597 + 0x19 bytes C
crasher.exe!mainCRTStartup() Line 414 C
kernel32.dll!7c817067()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]