-1

I am developing an application for Windows in Visual Studio 2015. The application runs three parallel processes: _thread_EEG (acquisition), _thread_MachineLearning (processing), _thread_Interface (interface). I'm using the libraries: <thread> <mutex>

class uMotor{
private:
    // Shared memory status
    std::mutex _Mutex_Buffer;
    std::mutex _Mutex_Label ;

    // Shared memory
    Raw  _Shared_buffer;
    char _Shared_label ;

    long _endTime;


    void _EEG            ();
    void _ML             ();
    void _Interface      ();

    static void _Thread_EEG(void *args){
        uMotor *prunnable = static_cast<uMotor*>(args);
        prunnable->_EEG();
    }

    static void _Thread_ML(void *args){
        uMotor *prunnable = static_cast<uMotor*>(args);
        prunnable->_ML();
    }

    static void _Thread_Interface(void *args){
        uMotor *prunnable = static_cast<uMotor*>(args);
        prunnable->_Interface();
    }
   /*
                      ...
    */
}

The threads are called in function uMotor::BCI():

void uMotor::BCI(){
    const long NUM_SECONDS_RUNNING = 20;

    long startTime = clock();
    _endTime = startTime + NUM_SECONDS_RUNNING * CLOCKS_PER_SEC;

    // Create threads
    std::thread std_Thread_EEG      (_Thread_EEG      );
    std::thread std_Thread_Interface(_Thread_Interface);
    std::thread std_Thread_ML       (_Thread_ML       );

    std_Thread_EEG      .join();
    std_Thread_Interface.join();
    std_Thread_ML       .join();
}

This code looks fine in the IDE (Visual Studio 2015) but when I try to compile it, I get the following errors:

Error C2672 'std::invoke': no matching overloaded function found uMotor c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread 240

Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)' uMotor c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread 240

What am I doing wrong?

Victor
  • 23
  • 5

2 Answers2

1

Threading support was added to C++ exactly for the reason to relieve developer from the need to use unsafe casts, pack values into void* structs, etc. With <thread> your code should be following (changed one function, you can do the rest):

std::thread std_Thread_EEG(&_EEG, this);
SergeyA
  • 61,605
  • 5
  • 78
  • 137
0

You are not passing the parameters that shall be passed to your functions to std::thread constructor, only the functions itself. This leads to trying to call _Thread_EEG() without parameters, but _Thread_EEG expects one (I'm using EEG as an example, of course applies for the other two, too).

What you actually need is

uMotor instance;
std::thread eeg(&_Thread_EEG, &instance); // or use this, if BCI is not static

std::thread's constructor is a template, so &instance is passed as uMotor* to _Thread_EEG, which allows you to declare it as

static void _Thread_EEG(uMotor* instance);

and you do not need the cast any more. I would prefer a reference, though:

static void _Thread_EEG(uMotor& instance);

Then, however, you need to make the reference explicit for thread template:

std::thread eeg(&_Thread_EEG, std::ref(instance)); // or std::ref(*this), if not static

By the way: have a look at here about identifiers starting with an underscore ('_')...

Community
  • 1
  • 1
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • Your answer have several issues. First, it gives the pointer to the different instance of `uMotor` (than the one used to create threads). This is likely not what OP wants. Second, you are unneccessary resolving scope for std. Since noone is to have namespace std in application code, this is not needed (same for the reference). Third, your statement *::std::thread is a template` is wrong. `std::thread` is **not** a template. – SergeyA Jun 02 '16 at 18:25
  • First issue isn't one - as assuming BCI to be static (thought it was clear from the comment in code), so `instance` is the only instance existing. You did assume, too (BCI not to be static), but declaration in uMotor is lacking, so both asumptions are valid. Second - but it is not illegal either. Still removed it to make you happy... Third: Accepted, it is not the class, only the constructor - adjusted the answer accordingly. – Aconcagua Jun 02 '16 at 20:00
  • Background for fully qualifying: In a company I used to work for scope resolution did not work correctly due to clashing sub-namespaces and usage of not fully qualified identifiers within a used library and some extension library we wrote on our own. Needed to change our own sub namespace, consequence was a rule to only use fully qualified identifers within library code. It was not my invention, but I tend to stick with it still today... – Aconcagua Jun 02 '16 at 20:06
  • Everyone has some bad experiences. But you have to be careful when you provide answers here - your code has a chance of being copypasted multiple times, so you'd better make it good code. – SergeyA Jun 02 '16 at 20:08
  • On the other hand: Fully qualifying does not break anything anywhere. Does it make bad code then? Searching for quarter an hour now, could not find anything stating fully qualifying is bad practice - or bad coding style at least... – Aconcagua Jun 02 '16 at 20:31
  • Yes, it is bad. It is not neccessary, it reduces signal-to-noise ration, it's non-standard (so it make your head spin - why is it there? Is it neccessary? is there an std namespace within this one). In short, **BAD THING**. If you do not trust me, you can ask as a question, – SergeyA Jun 02 '16 at 21:15
  • No, not necessary - thinking right about that, it is alike `return (a);`, `return (x + y);` or `if(x < y) return true; else return false;` instead of `return x < y;` (last one the very worst...) - all of which I hate to see... – Aconcagua Jun 02 '16 at 22:05