Currently I use:

DWORD ThreadProc(LPVOID lpParameter)
{
    void (* function)() = (void (*)())lpParameter;
    function();
    return 0;
}

void Threading(HANDLE &hThread, DWORD &ThreadID, void* FunctionToPass)
{
    hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (void*)FunctionToPass, 0, &ThreadID);
}

And I want to call it like:

Handle hThread; DWORD ThreadID;

Threading(hThread, ThreadID, AnyFunctionHere);

That way my Threading Function will create a thread and run any function. How can I pass it a function that has 0 or more parameters?

Recommended Answers

All 3 Replies

You can't make this work because the thread procedure need to know how many parameters does it have and what kind of parameters. Instead I would try using a va_list (stdarg.h), changing the Threading function like this:

void Threading(HANDLE &hThread, DWORD &ThreadID, void * FunctionToPass(int,...))
{
    hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc,(void*)FunctionToPass, 0, &ThreadID);
}

and the thread procedure will look like this:

DWORD ThreadProc(LPVOID lpParameter)
{
    void (* function)(int,...) = (void (*)(int,...))lpParameter;
    function(count,arg1,arg2,arg3,etc);
    return 0;
}

Each function that will be threaded must look like the one from the example of this page:
http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/

The second option will be making a class similar the Java thread class. There's a good example in this page:
http://kaisar-haque.blogspot.com/2007/07/c-nice-thread-class_23.html
You only need to create a derived class that will contain all the functions you want to thread.

Can't I do that same thing with variadic templates? I don't know how though :S

You don't need to use variadic templates for this. And you certainly don't want to go with the var-args solution that was suggested.

There is something called std::bind and std::function. The first allows you to bind any number of arguments to a function pointer and basically transform that function pointer into a different signature (and supply additional arguments). The second is a more general wrapper for all types of callable objects (function pointers / references, member-function pointers, functors, etc.), and that is the output of the bind function. In other words, you can do something like this:

double PNorm(double d1, double d2, int p) {
  return std::pow( std::pow(d1,p) + std::pow(d2,p), 1 / double(p) );
};

double Norm2(double d1, double d2) {
  return std::sqrt( d1 * d1 + d2 * d2 );
};

std::vector<double> GetNorms(const std::vector<double>& v1, const std::vector<double>& v2, std::function< double(double,double) > norm_function) {
  std::vector<double> result(v1.size());
  for(int i = 0; i < v1.size(); ++i)
    result[i] = norm_function(v1[i],v2[i]);
  return result;
};

int main() {
  std::vector<double> v1, v2);
  v1.push_back(0.5); v2.push_back(0.8);
  v1.push_back(2.0); v2.push_back(4.0);

  v_n2 = GetNorms(v1, v2, Norm2);
  std::cout << "Norm-2 are: " << v1[0] << " " << v2[1] << std::endl;

  v_n5 = GetNorms(v1, v2, std::bind(PNorm, _1, _2, 5)); // the _1 and _2 stand for argument one and two from the destination function signature.
  std::cout << "Norm-5 are: " << v_n5[0] << " " << v_n5[1] << std::endl;

  return 0;
};

I hope you get the idea. Read the cppreference pages on the subject, these things are also available in TR1 if you don't have a current compiler.

For your problem, instead of using a function pointer, use an nullary std::function, like so:

DWORD ThreadProc(LPVOID lpParameter)
{
    std::function< void() > func = *((std::function< void() >*)lpParameter);
    func();
    return 0;
}

And then you can construct any bindable function

void Threading(HANDLE &hThread, DWORD &ThreadID, std::function< void() >* FunctionToPass)
{
    hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (void*)FunctionToPass, 0, &ThreadID);
}

Remember, however, that your pointer to the std::function has to exist for the whole time of the thread, so it has to be created externally somehow and survive for as long as the thread that uses it survives.

However, if you want to save yourself all this trouble, just use the standard threads, as so:

void MyFunction(int, int);

int main() {
  std::thread t(std::bind(MyFunction, 42, 69));

  t.join(); // wait for the thread to finish.
  return 0;
};
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.