0

I'm facing a thread problem.

I tried to execute function inside a thread from Chronometer class including a while loop:

Here is the part code:

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;

The type of car_crono and chrono

std::vector<Chronometer*> car_crono;
Chronometer chrono;

Here is my class Chronometer:

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();

};

For the thread I tried several kind of parameters. The last one:

std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono));        

I guessed a ref was necessary but doesn't change.

Here is the full error

/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> >’

What kind of parameter should I pass through the thread ?

I went to several links to find a solution but nothing could solve my problem:

std::thread pass by reference calls copy constructor

No matching function to invoke, using std::thread

...

Thib
  • 11
  • 1
  • 4
  • 3
    `start_chrono` is a `static` member, you should not pass an object on which it would be called, only its parameters. – Yksisarvinen Aug 24 '21 at 10:53
  • There also seems to be a mismatch in the number of arguments. `std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono));` and `static Chronometer& start_chrono(Chronometer& chrono);` don't match. Also, what is the return value `Chronometer&` supposed to be? `std::thread` can't start functions returning anything (afaik). – Ted Lyngmo Aug 24 '21 at 11:16
  • The return value is the object "chrono" of type Chronometer which contains hour,min and sec. How can I do if I'm using void function ? – Thib Aug 24 '21 at 12:07
  • Well, perhaps you can start the thread - but how are you supposed to be able to get the actual return value from the starting function when the thread is done? Note that the join method `void std::thread::join();` is `void`. – Ted Lyngmo Aug 24 '21 at 12:21
  • @TedLyngmo No idea how to get the return value. I run my code by pushing several thread in a threads vector `threads.push_back(std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chrono)));` and then run the threads outside my first for loop `for (auto &th : threads) { th.join(); }` . My function works but not in background as expected for a thread and when function is over, my program crash: `terminate called after throwing an instance of 'std::system_error' what(): Argument invalide Abandon (core dumped)` – Thib Aug 24 '21 at 13:32
  • "_No idea how to get the return value_" - So, you could then just as well make the thread's starting function `void`. An alternative way of starting: [example](https://godbolt.org/z/nGor946rq) – Ted Lyngmo Aug 24 '21 at 13:33

1 Answers1

2

Chronometer::start_chrono is a static function, so it's not bound to any object, i.e doesn't need an object to called upon.

Static member functions are not associated with any object. When called, they have no this pointer.

You should have simply written.

std::thread(&Chronometer::start_chrono, std::ref(chrono));  
Karen Baghdasaryan
  • 2,407
  • 6
  • 24
  • or even `std::thread([&](){ Chronometer::start_chrono(chrono); });` – NathanOliver Aug 24 '21 at 11:13
  • @NathanOliver Or to be more precise in capturing only what you need. std::thread([&chrono](){ Chronometer::start_chrono(chrono); }); Though for short-lived threads (much shorter then application live cycle) I prefer using std::async. It will reuse threads from a threadpool managed by c++ runtime. auto ft = std::async(std::launch::async, [&chrono](){ Chronometer::start_chrono(chrono); }); – Pepijn Kramer Aug 24 '21 at 11:16
  • @PepijnKramer FWIW, on Mac and Linux, there is no thread pool backing `async`. I think MSVS is the only one that does. – NathanOliver Aug 24 '21 at 11:19
  • #Nathan A good to know, the standard indeed doesn't specify this is required. I am indeed used to running code on windows and there it is a nice bonus :) At least I like the futures returned from it, gives you return values to play with which thead::join misses. – Pepijn Kramer Aug 24 '21 at 11:24
  • @KarenBaghdasaryan Thanks, I wanted to use non-static function at the begining but compiler was asking me to use it in the thread due to syntax misunderstanding I guess. – Thib Aug 24 '21 at 12:45
  • @PepijnKramer How would you do without static function if you want to add car_crono[i] object of type Chronometer in std::async ? – Thib Aug 25 '21 at 08:21
  • @ThibaultGrard When sharing objects between threads, I usually use std::shared_ptr's and capture the pointer by value in the lambda. This ensures that as long as the lambda is alive (basically as long as the other thread is using it) the life-time of the object pointed to is extended. – Pepijn Kramer Aug 25 '21 at 08:52
  • @PepijnKramer Sorry but I'm beginner even more in thread and I do not understand any word you're talking about :( In my case, if start_chrono function is associated to car_crono vector containning for example two Chronometers objects. And from this two Chronometers object launch `start_chrono` in background with `std::async` to get at the end the final chrono result at a particular condition(for example if chrono.sec==30) of my two objects Chronometer. How could I solve this ? – Thib Aug 25 '21 at 09:09
  • @PepijnKramer I oppened a second issue here: [link] (https://stackoverflow.com/questions/68909406/terminate-called-after-throwing-an-instance-of-stdsystem-error/68911388#68911388) so you can see a test code I made but by using thread not std::async from future library – Thib Aug 25 '21 at 09:11