views:

139

answers:

4

Hello everyone,

I'm trying to learn how create new threads and run them. I need to pass a few variables into the function that is run on the new thread but I can't find out how to actually pass anything to that new function/thread.

I'm following http://www.devarticles.com/c/a/Cplusplus/Multithreading-in-C/1/ but it only goes through how to pass a single parameter and nothing else.

Side question, do threads work the exact same way as functions do except just on a different thread or is it a little more complicated than just that?

Thanks,

-Faken

+2  A: 

the single parameter have the size of a pointer. thus, you can fill a structure with as much information as you like and pass a pointer to this structure when creating a new thread, the same as you would do for passing a big structure into a function.

regarding thread execution, it works exactly the same, but it executes in parallel to other thread in your program. so, you have to take great care when accessing a global variable in your thread, because it may be accessed by some other thread at the same time.

Adrien Plisson
So that means I can't cleanly pass a few arrays into a new thread just like a regular function? I would need to pass a pointer to a structure which would then contain pointers to my heap arrays? Is there an easier more direct method?
Faken
that's pretty much the way you have to do it. It's not that bad anyway, compared to the other nightmares of threading. ;)
Marcus Lindblom
there is no easier method i can think of (but remember that an array is really a pointer to its first element, so do not overcomplicate the structure)
Adrien Plisson
Hmm...time to learn how to use structures properly...Is it possible to have a structure inside a structure? If not, things are going to get messy...actually either way its going to get messy.
Faken
yes, you can have a structure inside a structure, and nest as many depth of structure/class/union as you would like.
Adrien Plisson
+4  A: 

The underlying OS allows to pass only one parameter to a thread CreateThread:

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

Accordingly the CRT thread create function allows also only one parameter, despite the name being arglist:

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

Given these restrictions the usual convention is to pass a pointer to a structure/class with all the arguments. Usually, with C++, one creates a static function that will be the thread handler and passes an instance as the argument:

class Foo
{
  int _someState;
  int _otherState;
  char _moreState[256];

  unsigned DoWork();
  static unsigned ThreadHandler(void*);

public:
  void StartThread();
}

void Foo::StartThread()
{
   _beginthreadex(..., Foo::ThreadHandler, this, ...);
}

unsigned Foo::ThreadHandler(void* arglist)
{
   Foo* pFoo = (Foo*) arglist;
   return pFoo->DoWork();
}

unsigned Foo::DoWork()
{
  // do here all the thread work
}

This is a fairly common idiom and in effect it allows you to pass as much state (=arguments) as needed to the thread.

Remus Rusanu
+2  A: 

boost::thread lets you create threads with multiple parameters, if you want to give that a go. It's an alternative to the Windows thread APIs.

Steve Jessop
+1  A: 

I'll just rephrase Remus Rusanu's answer. If you pass a single parameter, that means you can pass arbitrary size of any data, as many people pointed out. Just send a pointer to a structure that includes what you want to pass. It's really simple. My suggestion is somewhat C-style while Remus Rusanu's C++ style maybe.

struct THREAD_DATA {
  int data1;
  struct MYSTRUCT data2;
  ...
};

void foo()
{
   ...
  // It's important not to pass a stack-allocated local structure.
  // That can be invalidated when this function exits.
  // So, safely allocated with malloc/new.
  THREAD_DATA* data = new THREAD_DATA;
  data->data1 = // put the value you want to pass
  data->data2 = //
  _beginthreadex(..., ThreadWorkerFunc, data, ...);
}


unsigned int CALLBACK ThreadWorkerFunc(void* arg)
{
  THREAD_DATA* data = (THREAD_DATA*)arg;
  ... = data->data1 


  delete data;
  return 0;
}
minjang