views:

324

answers:

5

I am trying to call the "Run" function in a new thread. Right now, I have this code using openMP that doesn't actually run "Run" in a new thread. NOTE: I am not asking for help using OpenMP. This code was just a quick fix. I would prefer a CreateThread() method of going about this.

vector<ICommand*>* commands;
string strInput;
// For each command...
for(vector<ICommand*>::iterator i = commands->begin(); i != commands->end(); ++i)
{
    // ...if the current command we're examining is valid...
    if((*i)->ContainsCommand(strInput))
    {
     // ...run it in a new thread and don't let ZChatInput handle it normally...
        #pragma omp sections nowait
     {
  #pragma omp section
   (*i)->Run(strInput);
  #pragma omp section
   bRet = false;
     }

     // ...and don't check any more commands.
     break;
    }

}

So how would this be done using just standard and STL? Of course, I'm looking for a way that works :)

+3  A: 

How about using Boost.Thread?

if((*i)->ContainsCommand(strInput))
{
    boost::thread t( boost::bind( &ICommand::Run, *i ) );
}

This will run "Run" in a detached thread. (Note, I did not test this.)

Martin Cote
No, sorry. I'm trying to shy away from 3rd party libraries. If this feature is in VS2010, then I'll try it out; but until then, still not what I'm looking for. Also, you forgot to pass strInput as a parameter.
Clark Gaebel
what's the problem with boost? It's almost as standard as stl. A lot of boost libraries are going into the new standard and I wouldn't be impressed if boost threads become the new standard (I know that there is a new standard for threads, but I don't know if they are similar to boost thread model)
Edison Gustavo Muenz
C++0x will have threading facilities that resemble boost.thread. See http://en.wikipedia.org/wiki/C%2B%2B0x#Threading_facilities
Martin Cote
Thank you for that, but it's unrelated to my problem. I'm still looking for a WinAPI solution to this.
Clark Gaebel
Any threading library will use the OS API in the end, so think about it like a wrapper.
Klaim
+1  A: 
Nikolai N Fetissov
It's NOT creating a thread for each command. It's only creating the thread if the input is valid, and no more. It MUST be asynchronous, as it gets really painfully slow otherwise. I don't understand your implementation strategy. Can you show some example pseudocode?
Clark Gaebel
It does... but it seems like a lot of work for a simple thread creation... There's gotta be a better way with CreateThread or some other WinAPI.
Clark Gaebel
Do you call Run() for every valid input? Then have the thread(s) pre-started. Otherwise you might find out that it's slower then single-threaded. And, yes, messing with threads is a lot of work.
Nikolai N Fetissov
And here's a link to MSDN docs for CreateThread:http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx
Nikolai N Fetissov
+2  A: 

like this? http://msdn.microsoft.com/en-us/library/kdzttdcb(VS.80).aspx

ryansstack
Can you show me in the context of the code I supplied?
Clark Gaebel
similar to the boost example, you use a pointer to your function as a parameter and up it goes. _beginthread and CreateThread are the MS functions for multithreading
DaClown
int h = (HANDLE)_beginthreadex(NULL,0,(*i)->Run,not exactly sure, and Run has to be a _stdcall function. This is a win32 api
ryansstack
It's __stdcall... all my functions are. I'll try it out, but what about the implicit "this" pointer? You're not passing that as a parameter.
Clark Gaebel
Sorry, I don't know what "this" pointer you're talking about. I have used this from a class to start an event handler, and passed "this" as the param argument _beginthreadex(NULL,0,function,this,0,NULL)then made the "function" a friend to my class. I had some difficulty running class member functions this way, so maybe this is not the droid you are looking for.
ryansstack
+2  A: 

You can try something like this:

vector<ICommand*>* commands;
string strInput;

void CommandOnThread(void* command)
{
    (ICommand*)command->Run();
}

// For each command...
for(vector<ICommand*>::iterator i = commands->begin(); i != commands->end(); ++i)
{
    // ...if the current command we're examining is valid...
    if((*i)->ContainsCommand(strInput))
    {
     //Attach the input to the command
     (*i)->AttachInput(strInput);
     _beginthread(CommandOnThread, 0, *i);
        break;
    }
}

For this you have to change the command interface a little for passing the command input in two steps: first store the input in the command object and then call Run() without arguments. You can replace _beginthread with CreateThread if you like they are quite similar.

Just to clarify: You can't use an instance method as the function parameter for _beginthread (or CreateThread). The solution above is to pass the object (command) to the function and then call its instance method (Run). However in that case you can't pass extra arguments to the thread function, and therefore can't pass arguments to the instance method. The easiest solution for this is to somehow attach the argument to the instance before passing it to the thread function.

I hope this helps. Of course this solution is not possible if you can't change the interface and implementation of the Command class.

Dani van der Meer
Where is "AttachInput" defined? Also, you're not passing any parameters to command->Run()
Clark Gaebel
You have to define it yourself. You can only pass one argument to the thread function, and it is already used for passing the command object.
Dani van der Meer
A: 

So I figured it out after double-checking the MSDN documentation. Here's how I did it, in case any of you are interested:

static vector<ICommand*>* commands;
// This is what we pass to CommandOnThread.
struct CommandParameter
{
    string strInput;
    ICommand* command;
};

int CommandOnThread(CommandParameter* cp)
{
 cp->command->Run(cp->strInput);
 delete cp;

 return 0;
}

void foo()
{
    string strInput;
    ...
    // For each command...
 for(vector<ICommand*>::iterator i = commands->begin(); i != commands->end(); ++i)
 {
  // ...if the current command we're examining is valid...
  if((*i)->ContainsCommand(strInput))
  {
   // Put the CP on the stack.
   CommandParameter* temp = new CommandParameter;
   if(temp == NULL)
   {
    Print("Out of memory!");
    bRet = false;
    break;
   }

   // ...set up the parameters to createthread...
   temp->strInput = strInput;
   temp->command = *i;

   // ...run it in a new thread...
   CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)CommandOnThread, temp, NULL, NULL);

   // ...and don't check any more commands.
   bRet = false;
   break;
  }
 }
}
Clark Gaebel