-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: