Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.

Problems with using parallel_do

Alexander_N_1
Beginner
326 Views

Hello. I've got next problem with using parallel_do: it even fails to compile if i pass std::bind result:

In file included from D:\Projects\MyProject\src\server.cpp:4:0:

D:/libs/tbb43_20150209/include/tbb/parallel_do.h: In instantiation of 'void tbb::parallel_do(Iterator, Iterator, const Body&) [with Iterator = long long unsigned int; Body = std::_Bind<void (*(std::_Placeholder<1>))(int&)>]':

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:492:74: required from 'void tbb::parallel_do(const Range&, const Body&) [with Range = tbb::blocked_range<long long unsigned int>; Body = std::_Bind<void (*(std::_Placeholder<1>))(int&)>]'

D:\Projects\MyProject\src\server.cpp:50:71: required from here

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:482:9: error: no matching function for call to 'select_parallel_do(long long unsigned int&, long long unsigned int&, const std::_Bind<void (*(std::_Placeholder<1>))(int&)>&, <unresolved overloaded function type>, tbb::task_group_context&)'

);

^

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:482:9: note: candidates are:

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:412:10: note: template<class Iterator, class Body, class Item> void tbb::internal::select_parallel_do(Iterator, Iterator, const Body&, void (Body::*)(Item) const, tbb::task_group_context&)

void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item) const

^

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:412:10: note: template argument deduction/substitution failed:

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:482:9: note: couldn't deduce template parameter 'Item'

);

^

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:429:10: note: template<class Iterator, class Body, class Item, class _Item> void tbb::internal::select_parallel_do(Iterator, Iterator, const Body&, void (Body::*)(Item, tbb::parallel_do_feeder<_Item>&) const, tbb::task_group_context&)

void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item, parallel_do_feeder<_Item>&) const

^

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:429:10: note: template argument deduction/substitution failed:

D:/libs/tbb43_20150209/include/tbb/parallel_do.h:482:9: note: couldn't deduce template parameter 'Item'

);

That's what my code do:

void print_item(int32_t& value) {
    //I know using iostreams like that is not thread safe i was just testing
    std::cout  << "value: " << value << std::endl;
}

int main(int argc, char** argv) {
    std::vector<int32_t> test;
    for(int i = 1; i <= 100; ++i) {
        test.push_back(i);
    }
    auto print_value = std::bind(&print_item,std::placeholders::_1); //this have special type _Bind
    std::function<void(int32_t&)> print_value_function = std::bind(&print_item,std::placeholders::_1); //this have special type _Bind
    tbb::parallel_do(test,print_value); //fails to compile
    tbb::parallel_do(test,print_value_function ); //compiles fine
}

Of course i can wrap those into std::function but that would add unnesessary overhead. Also i've found a problem in code using automatic argument type deduction in this code(and also in another places where it used):

    //! For internal use only.
    /** Detects types of Body's operator function arguments.
        @ingroup algorithms **/
    template<typename Iterator, typename Body, typename Item>
    void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item) const
#if __TBB_TASK_GROUP_CONTEXT
        , task_group_context& context 
#endif // __TBB_TASK_GROUP_CONTEXT 
        )
    {
        run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
#if __TBB_TASK_GROUP_CONTEXT
            , context
#endif // __TBB_TASK_GROUP_CONTEXT 
            );
    }

    //! For internal use only.
    /** Detects types of Body's operator function arguments.
        @ingroup algorithms **/
    template<typename Iterator, typename Body, typename Item, typename _Item>
    void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item, parallel_do_feeder<_Item>&) const
#if __TBB_TASK_GROUP_CONTEXT
        , task_group_context& context 
#endif // __TBB_TASK_GROUP_CONTEXT
        )
    {
        run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
#if __TBB_TASK_GROUP_CONTEXT
            , context
#endif // __TBB_TASK_GROUP_CONTEXT
            );
    }

I tried to use functional object where operator() is inherited from base class and Body type is different so that code fails to compile

0 Kudos
1 Reply
RafSchietekat
Valued Contributor III
326 Views

What overhead are you concerned about: performance-wise (presumed or measured?) or just syntactical? For the latter, it's probably doable (no pun intended) to use std::is_bind_expression to differentiate and std::function (from what you've found) to pick up operator(), and then maybe something more efficient if still desirable, but I haven't tried anything yet.

Did you use the keyword "override" for the overridden operator()? It might have alerted you about declaring the operator as "const". Only the "const" is required, though.

0 Kudos
Reply