4
votes

I have the following class which kicks off a new std::thread. I now want the thread to access a member variable of the class. So far I cannot work out how to do this. In my MyThread function I want to check m_Continue.

I have tried passing in 'this' when the thread is created but I get an error:

Error 1 error C2197: 'void (__cdecl *)(void)' : too many arguments for call c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional 1152 1 MyProject.

class SingletonClass
{
public:
    SingletonClass();
    virtual ~SingletonClass(){};

    static SingletonClass& Instance();
   void DoSomething();
private:
    static void MyThread();

    std::thread* m_Thread;
    bool m_Continue;
};

SingletonClass::SingletonClass()
{
    m_Continue = true;
    m_Thread= new std::thread(MyThread, this);
}

void SingletonClass::MyThread()
{
    while(this->m_Continue )
    {
       // do something
    }
}

void SingletonClass::DoSomething()
{
    m_Continue = false;
}

SingletonClass& SingletonClass::Instance()
{
    static SingletonClass _instance;
    return _instance;
}


int _tmain(int argc, _TCHAR* argv[])
{
    SingletonClass& singleton = SingletonClass::Instance();
    singleton.DoSomething();    

    return 0;
}

How can I do this??

3
Unrelated: there's no reason to allocate the thread dynamically, m_thread could simply be a std::thread that you assign: m_thread = std::thread{MyThread, this};. Also, your program has undefined behavior due to a data race on SingletonClass::m_Continue since it can potentially be accessed in the spawned thread while simultaneously being modified in the main thread. You need to either make it a std::atomic<bool> or protect accesses to it with a std::mutex.Casey

3 Answers

5
votes

If you want to access this from within the thread function, then it shouldn't be static:

void MyThread();

Now you can simply pass this as the second thread constructor argument, as you tried; but, being a non-static member, you'll need to qualify its name:

m_Thread= new std::thread(&SingletonClass::MyThread, this);

Alternatively, you might find a lambda easier to read:

m_Thread= new std::thread([this]{MyThread();});

But you shouldn't muck around with pointers and new like that; make the member variable a thread object and initialise it in the initialiser list:

SingletonClass::SingletonClass() :
    m_Continue(true), m_Thread([this]{MyThread();})
{}

making sure to declare m_Thread after any other members that it accesses; and make sure you stop and join the thread in the destructor, or earlier.

Finally, m_Continue should be std::atomic<bool> in order to set it on one thread and read it on another with well-defined behaviour.

3
votes

Replace

static void MyThread();

with

void MyThread();

as

this cannot be access within static method.

0
votes

You can access the member variable if it is public or you may make have a method like "bool shallContinue()" which returns m_Continue.

Now how do you do this. Check the below modified snippet:

static void SingletonClass::MyThread(SingleTonClass *arg)
{
    while(arg->shallContinue() )
    {
       // do something
    }
}

Below a complete example:

#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;

class A
{
public:
    A(int x) : a(x) 
    {
        thr = new thread(myThread, this);
    }
    static void myThread(A *arg)
    {
        arg->show();

    }
    void show()
    {
        cout << a << endl;
    }
private:
    int a;
    thread *thr;
};

int main()
{
    A a(1);
    sleep(2); 
    return 0;
}