简体   繁体   English

在不同的线程中调用std :: function

[英]Call std::function in different thread

I'm working in a c++ framework, mostly written before c++11, that allows us to fire events from a thread to a different thread (assuming that the receiving thread is running an event queue, so it's mainly used to fire events to the main UI thread from a helper thread). 我正在一个c ++框架中工作,主要是在c ++ 11之前编写的,它使我们能够将事件从线程触发到另一个线程(假设接收线程正在运行事件队列,因此它主要用于触发事件以主UI线程(来自帮助程序线程)。

Currently, the code to accomplish this is very verbose - it requires us to define two classes: 当前,实现此目的的代码非常冗长-需要我们定义两个类:

  1. An event class that contains any information we want to transfer. 一个事件类,其中包含我们要传输的任何信息。
  2. A listener class that handles the event in the receiving thread. 在接收线程中处理事件的侦听器类。

We've recently moved to c++11/14 and have been working on updating a lot of our code to use smart pointers, standard containers, and lambdas. 我们最近已移至c ++ 11/14,并一直在努力更新许多代码以使用智能指针,标准容器和lambda。 I'd like to write a generic class that allows me to send a lambda to be run in a different thread. 我想编写一个通用类,使我可以发送lambda以便在其他线程中运行。 Something like: 就像是:

mBoundary = make_unique<ThreadBoundary>( []( int value ) { doSomething( value ); } ); 
mBoundary->callInMainThread( 47 );

ThreadBoundary boundary2( []( std::string value ) { displayString( value ); } );
boundary2.callInMainThreadWait( "Show this string to the user" );

As an initial attempt, I've currently got this working with a lambda that doesn't take any parameters, built on top of the current framework functionality (omitting error checking, cleanup, etc): 作为最初的尝试,我目前正在使用不带任何参数的lambda进行工作,该lambda基于当前框架功能(省略错误检查,清除等)构建:

class ThreadBoundary
{
public:
    ThreadBoundary( std::function<void()> function ):mFunction( function )
    {
        mListener = make_shared<ThreadBoundaryListener>();
        cApplication::addThreadBoundaryListener( mListener );
    }

    void callInMainThread()
    {
        cApplication::fireEventInMainThread( new ThreadBoundaryEvent( mFunction ) );
    }

    class ThreadBoundaryEvent:public FrameworkThreadBoundaryEvent
    {
    public:
        ThreadBoundaryEvent( std::function<void()> function )
        {
            mFunction = function;
        }

        void call() { mFunction(); }

    private:
        std::function<void()> mFunction;
    };

    class ThreadBoundaryListener:public FrameworkThreadBoundaryListener
    {
    public:
        ThreadBoundaryListener() {}

        void handleEvent( const FrameworkThreadBoundaryEvent* event )
        {
            dynamic_cast<const ThreadBoundaryEvent*>( event )->call();
        }
    };

private:
    shared_ptr<ThreadBoundaryListener> mListener;
    std::function<void()> mFunction;
};

This allows me to fire "one-off" events to the main thread, however, without being able to send along parameters it's functionality is pretty limited. 这使我可以将“一次性”事件触发到主线程,但是,由于无法发送参数,因此它的功能非常有限。

I'd like to make this class use variadic templates so that I can pass anything to the callInMainThread function. 我想让此类使用可变参数模板,以便可以将任何内容传递给callInMainThread函数。 However, I haven't been able to figure out how to store the parameter pack in the event and pass it along to the function inside call() . 但是,我还无法弄清楚如何在事件中存储参数包并将其传递给call()内部的函数。 So my questions are: 所以我的问题是:

  1. Is it possible to store a parameter pack and later pass it to a std::function? 是否可以存储参数包,然后将其传递给std :: function?
  2. Is there a better way to do this in c++11/14 that doesn't require a huge redesign? 在c ++ 11/14中是否有更好的方法可以完成此操作,而无需进行大量重新设计? Our framework is currently wrapping OS functionality to accomplish this (ie on Windows it uses SendMessage vs performSelectorOnMainThread in OS X). 我们的框架目前正在包装OS功能以实现此目的(即,在Windows上,它使用OS X中的SendMessage与performSelectorOnMainThread)。

Instead of separating the interface construction from the invocation, use the power of the lambdas to capture arguments into the function object itself (a closure) so that every invocation is the same. 不要将接口构造与调用分开,而应使用lambda的功能将参数捕获到函数对象本身(闭包)中,以便每次调用都相同。 Don't have the basic thread communication object encapsulate a function type. 没有基本的线程通信对象封装函数类型。 Instead, pass the entire function as you call. 而是在调用时传递整个函数。 Go for this interface: 转到此界面:

threadBoundary.callInMainThread([value](){doSomething(value);});

If everything you pass is a function object that takes no parameters, it's easy to pass and easy to call. 如果您传递的所有内容都是不带参数的函数对象,那么传递和调用都很容易。 Capture anything you need to pass. 捕获您需要通过的所有内容。

For some interface and implementation ideas, look at how boost::asio implements its io_service , which allows you to post function calls to other threads just like this. 有关一些接口和实现的想法,请查看boost::asio如何实现其io_service ,它使您可以像这样将函数调用发布到其他线程。

A nullary function call is easier to send accross a thread boundary. 空函数调用更容易跨线程边界发送。 And it is easy to capture the arguments you want to pass into a lambda capture list. 而且很容易捕获要传递到lambda捕获列表中的参数。

I'd embrace that. 我会接受的。

However, you can write code to turn a non-nullary function call into a nullary one pretty easily. 但是,您可以编写代码将非空函数调用转换为空函数。 If you want to "freeze" the function call without the arguments, the signature must also be frozen. 如果要“冻结”不带参数的函数调用,则签名也必须冻结。

tempate<class Sig>
struct freeze_function;
tempate<class R, class...Args>
struct freeze_function<R(Args...)> {
  std::function< R(Args...) > to_freeze;
  freeze_function() = default;
  freeze_function( freeze_function&& ) = default;
  freeze_function( freeze_function const& ) = default;
  freeze_function& operator=( freeze_function&& ) = default;
  freeze_function& operator=( freeze_function const& ) = default;
  freeze_function( std::function< void(Args...) > f ):to_freeze(std::move(f)) {}

  std::function<R()> operator()( Args... args ) const {
    return [=, frozen=this->to_freeze]->R{
      return frozen( args... );
    };
  }
};

A freeze_function<void(int)> can be constructed from a lambda taking an int . 可以通过采用int的lambda构造freeze_function<void(int)> You can then pass it an int and it returns a std::function<void()> with that int bound. 然后,您可以将其传递给一个int并且它返回带有该int绑定的std::function<void()>

But I think this isn't required. 但是我认为这不是必需的。

(Extra work required to get optimal efficiency out of freeze_function ; it needlessly copies args... . I'd toss the args... into a tuple then unpack them within the lambda, maybe using the equivalent of std::apply from C++17.) (为了从freeze_function获得最佳效率需要进行额外的工作;它不必要地复制args...freeze_function args...扔到一个元组中,然后在lambda中解压缩它们,也许使用等效于std::apply from C ++ 17)。

This can be either baked into the ThreadBoundary by adding a signature (making it a template), or can be used to store your unrealized function calls somewhere and freezing them immediately prior to passing the resulting std::function<void()> to ThreadBoundary . 可以通过添加签名(使其成为模板)将其烘焙到ThreadBoundary ,也可以将未实现的函数调用存储在某个位置,并在将生成的std::function<void()>传递给ThreadBoundary之前立即冻结它们。 。

错误:没有匹配的 function 调用 'std::thread::_Invoker <std::tuple< div><div id="text_translate"><p> 我正面临线程问题。</p><p> 我试图在 Chronometer class 的线程内执行 function,包括一个 while 循环:</p><p> 这是部分代码:</p><pre> for(int i = 0; i<car_data.size();i++) { if(car_data[i]->checkArea(frame, pt1_zone, pt2_zone)) { std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono)); cv::rectangle(frame, car_data[i]->pt1, car_data[i]->pt2, cv::Scalar(255,0,0), 1, cv::LINE_8,0); //cv::putText(frame, "Parked", car_data[i]->pt1, cv::FONT_HERSHEY_DUPLEX, 0.9, cv::Scalar( 50, 255, 50 )); //occupancy_state = place.occupancyTrue(); //place_1.occupancy = true;</pre><p> car_crono 和 chrono 的类型</p><pre>std::vector<Chronometer*> car_crono; Chronometer chrono;</pre><p> 这是我的 class 计时器:</p><pre> class Chronometer { private: static int hour, min, sec; //std::stringstream ss; //Chronometer chrono; public: Chronometer(); static Chronometer& start_chrono(Chronometer& chrono); static Chronometer& finish_chrono(Chronometer& chrono); friend std::ostream& operator<<(std::ostream& flux, Chronometer t); Chronometer& operator=(const Chronometer& other); ~Chronometer(); };</pre><p> 对于线程,我尝试了几种参数。 最后一个:</p><pre> std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono));</pre><p> 我猜 ref 是必要的,但没有改变。</p><p> 这是完整的错误</p><pre>/usr/include/c++/7/thread: In instantiation of 'struct std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >': /usr/include/c++/7/thread:127:22: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*&, std::reference_wrapper<Chronometer>}]' recognizer_rtsp.cxx:348:76: required from here /usr/include/c++/7/thread:240:2: error: no matching function for call to 'std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_M_invoke(std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_Indices)' operator()() ^~~~~~~~ /usr/include/c++/7/thread:231:4: note: candidate: template<long unsigned int..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind...>) [with long unsigned int..._Ind = {_Ind...}; _Tuple = std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> >] _M_invoke(_Index_tuple<_Ind...>) ^~~~~~~~~ /usr/include/c++/7/thread:231:4: note: template argument deduction/substitution failed: /usr/include/c++/7/thread: In substitution of 'template<long unsigned int..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_M_invoke<_Ind...>(std::_Index_tuple<_Ind1...>) [with long unsigned int..._Ind = {0, 1, 2}]': /usr/include/c++/7/thread:240:2: required from 'struct std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >' /usr/include/c++/7/thread:127:22: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*&, std::reference_wrapper<Chronometer>}]' recognizer_rtsp.cxx:348:76: required from here /usr/include/c++/7/thread:233:29: error: no matching function for call to '__invoke(std::__tuple_element_t<0, std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >, std::__tuple_element_t<1, std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >, std::__tuple_element_t<2, std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >)' -> decltype(std::__invoke(_S_declval<_Ind>()...)) ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/7/tuple:41:0, from /usr/include/c++/7/bits/stl_map.h:63, from /usr/include/c++/7/map:61, from../alpr_utils.h:7, from recognizer_rtsp.cxx:34: /usr/include/c++/7/bits/invoke.h:89:5: note: candidate: template<class _Callable, class... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&&...) __invoke(_Callable&& __fn, _Args&&... __args) ^~~~~~~~ /usr/include/c++/7/bits/invoke.h:89:5: note: template argument deduction/substitution failed: /usr/include/c++/7/bits/invoke.h: In substitution of 'template<class _Callable, class... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*, std::reference_wrapper<Chronometer>}]': /usr/include/c++/7/thread:233:29: required by substitution of 'template<long unsigned int..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_M_invoke<_Ind...>(std::_Index_tuple<_Ind1...>) [with long unsigned int..._Ind = {0, 1, 2}]' /usr/include/c++/7/thread:240:2: required from 'struct std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >' /usr/include/c++/7/thread:127:22: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*&, std::reference_wrapper<Chronometer>}]' recognizer_rtsp.cxx:348:76: required from here /usr/include/c++/7/bits/invoke.h:89:5: error: no type named 'type' in 'struct std::__invoke_result<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> >'</pre><p> 我应该通过线程传递什么样的参数?</p><p> 我去了几个链接来寻找解决方案,但没有什么能解决我的问题:</p><p> <a href="https://stackoverflow.com/questions/21048906/stdthread-pass-by-reference-calls-copy-constructor" rel="nofollow noreferrer">std::thread 通过引用传递调用复制构造函数</a></p><p> <a href="https://stackoverflow.com/questions/67625058/no-matching-function-to-invoke-using-stdthread" rel="nofollow noreferrer">没有匹配的 function 调用,使用 std::thread</a></p><p> ... </p></div></std::tuple<> - error: no matching function for call to ‘std::thread::_Invoker<std::tuple

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 包装std :: thread调用函数 - Wrap std::thread call function 使用std :: async从线程进行函数调用? - Using std::async for function call from thread? 错误:没有用于调用 std::thread 的匹配函数 - error: no matching function for call to std::thread 使用不同的参数函数运行std :: thread - Running std::thread with different argument function 错误:没有匹配的 function 调用 'std::thread::_Invoker <std::tuple< div><div id="text_translate"><p> 我正面临线程问题。</p><p> 我试图在 Chronometer class 的线程内执行 function,包括一个 while 循环:</p><p> 这是部分代码:</p><pre> for(int i = 0; i<car_data.size();i++) { if(car_data[i]->checkArea(frame, pt1_zone, pt2_zone)) { std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono)); cv::rectangle(frame, car_data[i]->pt1, car_data[i]->pt2, cv::Scalar(255,0,0), 1, cv::LINE_8,0); //cv::putText(frame, "Parked", car_data[i]->pt1, cv::FONT_HERSHEY_DUPLEX, 0.9, cv::Scalar( 50, 255, 50 )); //occupancy_state = place.occupancyTrue(); //place_1.occupancy = true;</pre><p> car_crono 和 chrono 的类型</p><pre>std::vector<Chronometer*> car_crono; Chronometer chrono;</pre><p> 这是我的 class 计时器:</p><pre> class Chronometer { private: static int hour, min, sec; //std::stringstream ss; //Chronometer chrono; public: Chronometer(); static Chronometer& start_chrono(Chronometer& chrono); static Chronometer& finish_chrono(Chronometer& chrono); friend std::ostream& operator<<(std::ostream& flux, Chronometer t); Chronometer& operator=(const Chronometer& other); ~Chronometer(); };</pre><p> 对于线程,我尝试了几种参数。 最后一个:</p><pre> std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono));</pre><p> 我猜 ref 是必要的,但没有改变。</p><p> 这是完整的错误</p><pre>/usr/include/c++/7/thread: In instantiation of 'struct std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >': /usr/include/c++/7/thread:127:22: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*&, std::reference_wrapper<Chronometer>}]' recognizer_rtsp.cxx:348:76: required from here /usr/include/c++/7/thread:240:2: error: no matching function for call to 'std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_M_invoke(std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_Indices)' operator()() ^~~~~~~~ /usr/include/c++/7/thread:231:4: note: candidate: template<long unsigned int..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind...>) [with long unsigned int..._Ind = {_Ind...}; _Tuple = std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> >] _M_invoke(_Index_tuple<_Ind...>) ^~~~~~~~~ /usr/include/c++/7/thread:231:4: note: template argument deduction/substitution failed: /usr/include/c++/7/thread: In substitution of 'template<long unsigned int..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_M_invoke<_Ind...>(std::_Index_tuple<_Ind1...>) [with long unsigned int..._Ind = {0, 1, 2}]': /usr/include/c++/7/thread:240:2: required from 'struct std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >' /usr/include/c++/7/thread:127:22: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*&, std::reference_wrapper<Chronometer>}]' recognizer_rtsp.cxx:348:76: required from here /usr/include/c++/7/thread:233:29: error: no matching function for call to '__invoke(std::__tuple_element_t<0, std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >, std::__tuple_element_t<1, std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >, std::__tuple_element_t<2, std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >)' -> decltype(std::__invoke(_S_declval<_Ind>()...)) ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/7/tuple:41:0, from /usr/include/c++/7/bits/stl_map.h:63, from /usr/include/c++/7/map:61, from../alpr_utils.h:7, from recognizer_rtsp.cxx:34: /usr/include/c++/7/bits/invoke.h:89:5: note: candidate: template<class _Callable, class... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&&...) __invoke(_Callable&& __fn, _Args&&... __args) ^~~~~~~~ /usr/include/c++/7/bits/invoke.h:89:5: note: template argument deduction/substitution failed: /usr/include/c++/7/bits/invoke.h: In substitution of 'template<class _Callable, class... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*, std::reference_wrapper<Chronometer>}]': /usr/include/c++/7/thread:233:29: required by substitution of 'template<long unsigned int..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >::_M_invoke<_Ind...>(std::_Index_tuple<_Ind1...>) [with long unsigned int..._Ind = {0, 1, 2}]' /usr/include/c++/7/thread:240:2: required from 'struct std::thread::_Invoker<std::tuple<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> > >' /usr/include/c++/7/thread:127:22: required from 'std::thread::thread(_Callable&&, _Args&&...) [with _Callable = Chronometer& (*)(Chronometer&); _Args = {Chronometer*&, std::reference_wrapper<Chronometer>}]' recognizer_rtsp.cxx:348:76: required from here /usr/include/c++/7/bits/invoke.h:89:5: error: no type named 'type' in 'struct std::__invoke_result<Chronometer& (*)(Chronometer&), Chronometer*, std::reference_wrapper<Chronometer> >'</pre><p> 我应该通过线程传递什么样的参数?</p><p> 我去了几个链接来寻找解决方案,但没有什么能解决我的问题:</p><p> <a href="https://stackoverflow.com/questions/21048906/stdthread-pass-by-reference-calls-copy-constructor" rel="nofollow noreferrer">std::thread 通过引用传递调用复制构造函数</a></p><p> <a href="https://stackoverflow.com/questions/67625058/no-matching-function-to-invoke-using-stdthread" rel="nofollow noreferrer">没有匹配的 function 调用,使用 std::thread</a></p><p> ... </p></div></std::tuple<> - error: no matching function for call to ‘std::thread::_Invoker<std::tuple C ++ 11 std :: thread给出错误:没有匹配函数来调用std :: thread :: thread - C++11 std::thread giving error: no matching function to call std::thread::thread std :: function vs auto调用不同的重载 - std::function vs auto call to different overload std线程调用模板成员函数模板类:编译错误 - std thread call template member function of template class: compiler error 使用char指针函数和std :: string调用线程会产生不同的结果 - Calling thread with char pointer function and std::string produces different results 用函数构造一个std :: thread - Constructing a std::thread with a function
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM