0

Code 1:

class thread_obj {
private:
    static int instances;
    bool run;
    static mutex lock;
    int threadno;
    static map<int, thread> mapOfThreads;
public:
    thread_obj():run(true)
    {
        lock.lock();
        threadno = instances++;
        thread th(thread_obj::thredfunc, this);
        mapOfThreads[threadno] = move(th);

        cout << "Thread no is " << threadno << endl;
        lock.unlock();
    }
    static void thredfunc(thread_obj* ptr)
    {
        while (ptr->run)
        {
            std::this_thread::sleep_for(100ms);
        }
    }

    void operator()()
    {
        while (run)
        {
            std::this_thread::sleep_for(100ms);
        }
    }

    void stop()
    {
        run = false;
    }

    static int getTotalthreads()
    {
        return mapOfThreads.size();
    }

    ~thread_obj()
    {
        lock.lock();
        stop();
        if (mapOfThreads[threadno].joinable())
            mapOfThreads[threadno].join();
        mapOfThreads.erase(threadno);
        cout << "Destroyed " << threadno << endl;
        lock.unlock();
    }
};
int thread_obj::instances = 0;
mutex thread_obj::lock;
map<int, thread> thread_obj::mapOfThreads;

Code 2:

thread_obj():run(true)
{
    lock.lock();
    threadno = instances++;
    thread th(thread_obj(), this);
    mapOfThreads[threadno] = move(th);

    cout << "Thread no is " << threadno << endl;
    lock.unlock();
}

First code works fine, but changing constructor like given in code 2 gives error. In code 1 constructor create thread from static function.In code two constructor calls non static operator()

  1. 'std::invoke': no matching overloaded function found
  2. Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept(<expr>)'

What is the reason behind this? (This code is created to handle multiple threads.)

Varun Rao
  • 29
  • 4
  • Aren't the two pieces of code the same? Also, why are you manually calling `lock()` and `unlock()` instead of using a scoped lock like [`std::lock_guard`](https://en.cppreference.com/w/cpp/thread/lock_guard)? What would happen if one of the statements in your constructor threw an exception? – Jonathan Wakely Jul 11 '19 at 08:32
  • Please add a [mre], your 2 posted samples are identical – Alan Birtles Jul 11 '19 at 08:34
  • 1
    You probably meant to write `std::thread th(std::ref(*this));` instead of `std::thread th(thread_obj(), this);` because the latter is nonsense. – Jonathan Wakely Jul 11 '19 at 08:34
  • What is this supposed to be doing: `thread th(thread_obj(), this);` ? And what is the point of the static member `thredfunc`, which appears entirely unused in either code list? – WhozCraig Jul 11 '19 at 08:37
  • I assume the "working" code is _supposed_ to be using `thread th(thredfunc, this);` which _would_ compile. I guess the OP is trying to replace the static `thread_func` version with the member `operator()`, but getting the syntax wrong. Ah yes, it just got edited, I guessed right. – Jonathan Wakely Jul 11 '19 at 08:41
  • 1. this is what worked --> thread th(std::ref(*this)); 2. Non static thredfunc like this --> thread th(thredfunc, this); did not work 3. Static functon with argument ( static void thredfunc(thread_obj* ptr) ) worked – Varun Rao Jul 11 '19 at 08:54
  • @JonathanWakely Thank you. Using lock_guardmutexlock(lock); now – Varun Rao Jul 11 '19 at 09:00
  • @VarunRao `thread th(thredfunc, this)` won't work because 1. that's not how you create a pointer to a non-static member function and 2. if you still have the other function called `thredfunc` then now you have an overloaded name that can't be used like that at all. Read my answer more carefully and try what I suggested, not something different. It will work if you do it properly. – Jonathan Wakely Jul 11 '19 at 09:02

1 Answers1

2

This line in the constructor is nonsense:

    thread th(thread_obj(), this);

This will construct another thread_obj() object, then try to invoke it in a new thread passing it the this pointer, i.e. a thread_obj* pointer. That would only work if the operator() function took a thread_obj* argument, but it doesn't.

I think what you're trying to do is run this->operator()() in a new thread, so you would do that like this:

thread th(std::ref(*this));

This creates the new thread with a reference to *this and then it will invoke it like (*this)(), which will call operator()(). Alternatively, rename the operator() function to give it a proper name, for example:

void thread_func()
{
    while (run)
    {
        std::this_thread::sleep_for(100ms);
    }
}

And then in the constructor pass a pointer-to-member-function to the std::thread constructor, with this as the object to call that member function on:

thread th(&thread_obj::thread_func, this);

There are hundreds of existing questions on stackoverflow explaining how to run a member function in a std::thread.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • I tried your last suggestion ( thread th(&thread_obj::thredfunc, this); ). It is showing error no instance of constructor "std::thread::thread" matches the argument list – Varun Rao Jul 11 '19 at 08:49
  • That's not what I suggested though, you've got it wrong. I said to rename the function to `thread_func` and use that, you've tried to use the static `thredfunc` again. – Jonathan Wakely Jul 11 '19 at 08:51
  • Got it, Thank you. – Varun Rao Jul 11 '19 at 09:07