-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Possible lifetime issue with parallel_scan over non trivially destructible range #1390
Comments
I can reproduce the issue. It does appear that sometimes the right zombie child self destructs without being fully constructed. |
If that helps, here is a little patch that fixes lifetime problem for me
Of course, it doesn't fix the cause of why it wants to self destruct at wrong time. |
We are still looking into why the object is left uninitialized. Meanwhile, I hope that you are able to use the workaround (even a simple |
Hello, Update on issue status so far:
Looks like I've traced the cause down to Here is slightly reworked example, that can now detect these issues: BOOST_AUTO_TEST_CASE( tbb_scan )
{
std::vector <int> vec;
const int len = 34479;
static std::atomic_int rng_error = 0;
static std::atomic_int obj_error = 0;
static std::atomic_int obj_count = 0;
struct non_trivial_range : tbb::blocked_range <decltype(vec)::iterator>
{
using non_trivial_range::blocked_range::blocked_range;
~non_trivial_range()
{
if (cookie != 0xFEE1C001)
++rng_error;
std::this_thread::yield(); // imitate some cleanup procedure
cookie = 0xDEADBEEF;
}
unsigned cookie = 0xFEE1C001;
};
struct non_trivial_scanner
{
non_trivial_scanner() { ++obj_count; }
non_trivial_scanner( non_trivial_scanner &, tbb::split ) noexcept { ++obj_count; }
non_trivial_scanner( non_trivial_scanner const & ) = delete;
~non_trivial_scanner()
{
if (cookie != 0xFEE1600D)
++obj_error;
std::this_thread::yield(); // imitate some cleanup procedure
cookie = 0xDEADF00D;
--obj_count;
}
unsigned cookie = 0xFEE1600D;
int sum = 0;
void operator()( const non_trivial_range & r, tbb::final_scan_tag ) { for (int p : r) sum += p; }
void operator()( const non_trivial_range & r, tbb::pre_scan_tag ) { for (int p : r) sum += p; }
void reverse_join( non_trivial_scanner & lhs ) { sum += lhs.sum; }
void assign( non_trivial_scanner & other ) { sum = other.sum; }
};
vec.assign( len, 1 );
for (int i = 0; i < 100'000; ++i) BOOST_TEST_CONTEXT( "run " << i )
{
non_trivial_scanner nts;
BOOST_REQUIRE_EQUAL( obj_count, 1 );
tbb::parallel_scan( non_trivial_range{ vec.begin(), vec.end() }, nts );
const int oc = obj_count.load();
BOOST_REQUIRE_EQUAL( oc, 1 );
BOOST_REQUIRE_EQUAL( obj_error, 0 );
BOOST_REQUIRE_EQUAL( rng_error, 0 );
BOOST_REQUIRE_EQUAL( nts.sum, len );
if ((i % 1000) == 0)
std::cout << i << std::endl;
}
} |
Hi,
I've faced odd crash using parallel_scan over range object that has some logic inside its destructor. It seems that destructor of range sometimes called on not yet constructed range object.
It happens not 100% times, but there is a minimal reproducible example I managed to get (ensure asserts are on):
tbb.cpp.txt
Tested on:
Is there a problem inside my code?
Regards,
Slava
The text was updated successfully, but these errors were encountered: