store parallel executor as a member variable causing crash
niyue opened this issue · comments
I would like to re-use transwarp's parallel executor for transforming data multiple times, so I store it as a class's member variable like this:
class Transformer {
public:
vector<int> transform(vector<int> &data) {
vector<int> result(data.size());
auto t = tw::transform(_exec, data.begin(), data.end(), result.begin(),
[&](int x) { return x * 2; });
return result;
}
private:
tw::parallel _exec{1};
};
TEST_CASE("transwarp test") {
Transformer t;
auto data = vector<int>{1, 2, 3};
auto r = t.transform(data);
REQUIRE(r.size() == 3);
}
But this will cause crash on macOS Big Sur (11.3.1), with stack like this:
Thread 1 Crashed:
0 libsystem_platform.dylib 0x00007fff2061650c _os_unfair_lock_recursive_abort + 23
1 libsystem_platform.dylib 0x00007fff20611125 _os_unfair_lock_lock_slow + 258
2 libsystem_malloc.dylib 0x00007fff203f90e5 free_tiny + 134
3 tracing-tests 0x000000010bed15a5 std::__1::_DeallocateCaller::__do_call(void*) + 21 (new:334)
4 tracing-tests 0x000000010bed1559 std::__1::_DeallocateCaller::__do_deallocate_handle_size(void*, unsigned long) + 25 (new:292)
5 tracing-tests 0x000000010bf4fbf5 std::__1::_DeallocateCaller::__do_deallocate_handle_size_align(void*, unsigned long, unsigned long) + 85 (new:268)
6 tracing-tests 0x000000010bf4fb95 std::__1::__libcpp_deallocate(void*, unsigned long, unsigned long) + 37 (new:340)
7 tracing-tests 0x000000010bf78a0d std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::deallocate(std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, unsigned long) + 45 (memory:1673)
8 tracing-tests 0x000000010bf78865 std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > >::deallocate(std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&, std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, unsigned long) + 37 (memory:1408)
9 tracing-tests 0x000000010bf787f4 std::__1::__split_buffer<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&>::~__split_buffer() + 100 (__split_buffer:350)
10 tracing-tests 0x000000010bf77fb5 std::__1::__split_buffer<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&>::~__split_buffer() + 21 (__split_buffer:347)
11 tracing-tests 0x000000010bf779ba void std::__1::vector<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > >::__push_back_slow_path<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&&) + 186 (vector:1632)
12 tracing-tests 0x000000010bf77757 std::__1::vector<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::allocator<std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > >::push_back(std::__1::unique_ptr<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::default_delete<std::__1::basic_ostringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&&) + 103 (vector:1659)
13 tracing-tests 0x000000010bf34a96 Catch::StringStreams::add() + 134 (catch.hpp:13662)
14 tracing-tests 0x000000010bf34979 Catch::ReusableStringStream::ReusableStringStream() + 73 (catch.hpp:13679)
15 tracing-tests 0x000000010bf1ab45 Catch::ReusableStringStream::ReusableStringStream() + 21 (catch.hpp:13681)
16 tracing-tests 0x000000010bf2b745 Catch::MessageStream::MessageStream() + 21 (catch.hpp:2623)
17 tracing-tests 0x000000010bf2b70a Catch::MessageBuilder::MessageBuilder(Catch::StringRef const&, Catch::SourceLineInfo const&, Catch::ResultWas::OfType) + 42 (catch.hpp:11782)
18 tracing-tests 0x000000010bf24bab Catch::MessageBuilder::MessageBuilder(Catch::StringRef const&, Catch::SourceLineInfo const&, Catch::ResultWas::OfType) + 43 (catch.hpp:11785)
19 tracing-tests 0x000000010bf249d9 Catch::AssertionStats::AssertionStats(Catch::AssertionResult const&, std::__1::vector<Catch::MessageInfo, std::__1::allocator<Catch::MessageInfo> > const&, Catch::Totals const&) + 297 (catch.hpp:11044)
20 tracing-tests 0x000000010bf24ced Catch::AssertionStats::AssertionStats(Catch::AssertionResult const&, std::__1::vector<Catch::MessageInfo, std::__1::allocator<Catch::MessageInfo> > const&, Catch::Totals const&) + 45 (catch.hpp:11038)
21 tracing-tests 0x000000010bf2f48a Catch::RunContext::assertionEnded(Catch::AssertionResult const&) + 330 (catch.hpp:12708)
22 tracing-tests 0x000000010bf308ec Catch::RunContext::handleFatalErrorCondition(Catch::StringRef) + 268 (catch.hpp:12831)
23 tracing-tests 0x000000010bf24320 (anonymous namespace)::reportFatal(char const*) + 64 (catch.hpp:10756)
24 tracing-tests 0x000000010bf2423f Catch::FatalConditionHandler::handleSignal(int) + 143 (catch.hpp:10850)
25 libsystem_platform.dylib 0x00007fff20612d7d _sigtramp + 29
26 ??? 0x0000000000008fd0 0 + 36816
27 libsystem_malloc.dylib 0x00007fff203f97b3 tiny_free_no_lock + 1112
28 libsystem_malloc.dylib 0x00007fff203f9219 free_tiny + 442
29 tracing-tests 0x000000010bf033b7 std::__1::default_delete<transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> > >::operator()(transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> >*) const + 55 (memory:2084)
30 tracing-tests 0x000000010bf03089 std::__1::__shared_ptr_pointer<transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> >*, std::__1::shared_ptr<transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> > >::__shared_ptr_default_delete<transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> >, transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> > >, std::__1::allocator<transwarp::detail::runner<void, transwarp::root_type, transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>, std::__1::tuple<> > > >::__on_zero_shared() + 89 (memory:3265)
31 tracing-tests 0x000000010bedbdfd std::__1::__shared_count::__release_shared() + 61 (memory:3169)
32 tracing-tests 0x000000010bedbd9f std::__1::__shared_weak_count::__release_shared() + 31 (memory:3211)
33 tracing-tests 0x000000010bedbd6c std::__1::shared_ptr<jaegertracing::Tracer>::~shared_ptr() + 44 (memory:3884)
34 tracing-tests 0x000000010becaad5 std::__1::shared_ptr<opentracing::v3::Tracer>::~shared_ptr() + 21 (memory:3882)
35 tracing-tests 0x000000010befb225 transwarp::detail::add_listener_visitor::~add_listener_visitor() + 21 (transwarp.h:1328)
36 tracing-tests 0x000000010befb0b5 transwarp::detail::add_listener_visitor::~add_listener_visitor() + 21 (transwarp.h:1328)
37 tracing-tests 0x000000010bf04205 std::__1::__compressed_pair_elem<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'(), 0, false>::~__compressed_pair_elem() + 21 (memory:1909)
38 tracing-tests 0x000000010bf04448 std::__1::__compressed_pair<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'(), std::__1::allocator<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'()> >::~__compressed_pair() + 24 (memory:1983)
39 tracing-tests 0x000000010bf04425 std::__1::__compressed_pair<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'(), std::__1::allocator<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'()> >::~__compressed_pair() + 21 (memory:1983)
40 tracing-tests 0x000000010bf06b15 std::__1::__function::__alloc_func<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'(), std::__1::allocator<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'()>, void ()>::destroy() + 21 (functional:1572)
41 tracing-tests 0x000000010bf057ce std::__1::__function::__func<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'(), std::__1::allocator<transwarp::detail::task_impl_base<void, transwarp::root_type, std::__1::shared_ptr<transwarp::task_impl<transwarp::wait_type, transwarp::no_op_functor, std::__1::vector<std::__1::shared_ptr<transwarp::task<void> >, std::__1::allocator<std::__1::shared_ptr<transwarp::task<void> > > > > > transwarp::transform<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int)>(std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, Transformer::transform(std::__1::vector<int, std::__1::allocator<int> >&)::'lambda'(int))::'lambda'()>::schedule_impl(bool, transwarp::executor*)::'lambda0'()>, void ()>::destroy() + 30 (functional:1709)
42 tracing-tests 0x000000010bee7b45 std::__1::__function::__value_func<void ()>::~__value_func() + 53 (functional:1839)
43 tracing-tests 0x000000010bee7b05 std::__1::__function::__value_func<void ()>::~__value_func() + 21 (functional:1837)
44 tracing-tests 0x000000010bee7ae5 std::__1::function<void ()>::~function() + 21 (functional:2542)
45 tracing-tests 0x000000010bee70c5 std::__1::function<void ()>::~function() + 21 (functional:2542)
46 tracing-tests 0x000000010bee5f3f transwarp::detail::thread_pool::worker(unsigned long) + 447 (transwarp.h:786)
47 tracing-tests 0x000000010bee899f decltype(*(std::__1::forward<transwarp::detail::thread_pool*>(fp0)).*fp(std::__1::forward<unsigned long>(fp1))) std::__1::__invoke<void (transwarp::detail::thread_pool::*)(unsigned long), transwarp::detail::thread_pool*, unsigned long, void>(void (transwarp::detail::thread_pool::*&&)(unsigned long), transwarp::detail::thread_pool*&&, unsigned long&&) + 143 (type_traits:3688)
48 tracing-tests 0x000000010bee8897 void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (transwarp::detail::thread_pool::*)(unsigned long), transwarp::detail::thread_pool*, unsigned long, 2ul, 3ul>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (transwarp::detail::thread_pool::*)(unsigned long), transwarp::detail::thread_pool*, unsigned long>&, std::__1::__tuple_indices<2ul, 3ul>) + 87 (thread:280)
49 tracing-tests 0x000000010bee7fb6 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (transwarp::detail::thread_pool::*)(unsigned long), transwarp::detail::thread_pool*, unsigned long> >(void*) + 118 (thread:291)
50 libsystem_pthread.dylib 0x00007fff205cd954 _pthread_start + 224
51 libsystem_pthread.dylib 0x00007fff205c94a7 thread_start + 15
I have to move the executor as a local variable instead of a instance member variable like below:
class Transformer {
public:
vector<int> transform(vector<int> &data) {
vector<int> result(data.size());
tw::parallel exec{1}; // use it as a local variable
auto t =
tw::transform(exec, data.begin(), data.end(), result.begin(), [&](int x) { return x * 2; });
return result;
}
private:
// tw::parallel exec{1}; // have to commit it out
};
I searched all the tests in the repo but cannot find an example like this, is the executor expected to be used as an instance variable like above? I think if I make it as a local variable, the thread pool will be launched every time I call the transform
, what would be the correct approach for re-using the thread pool for multiple times of transformation? Thanks.
I think this is happening because t
may not be finished running before transform
returns. One of the assumptions of transwarp is that the tasks in a transwarp graph outlive their computations. So, in order to fix the bug here you need to wait for tasks to finish computing:
class Transformer {
public:
vector<int> transform(vector<int> &data) {
vector<int> result(data.size());
auto t = tw::transform(_exec, data.begin(), data.end(), result.begin(),
[&](int x) { return x * 2; });
t->wait(); // <- this is new
return result;
}
private:
tw::parallel _exec{1};
};
I think this makes a lot of sense here because otherwise result
may not be fully populated but you're already returning. Note that tw::transform
is non-blocking.
@bloomen thanks for your quick reply. You are right and I realized I made some mistake when posting this issue. I tried to narrow down the problem from a large code base, and wrote this small test case for verification and somehow posted an intermediate revision without this t->wait()
line when when posting this issue (sorry for the confusion).
And thanks to your prompt, I figured out the cause of my code. I understood that tw::transform
is non blocking, and in my large code base, I tried to use task->get()
API to wait for the computation to finish and throw an exception if there is any error. However, I made a stupid mistake and typed it as task.get()
instead of task->get()
. Since the task
returned by tw::transform
is a shared_ptr
, the task.get()
actually calls the shared_ptr.get()
to return a pointer instead of transwarp's task get
API, which essentially led to the same result as without this line (causing the crash). And compiler is happy to accept the code because shared_ptr
has a get
function as well :(
Thanks so much for the help!