Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible in C++ to execute function in main thread from function that is running in secondary thread?

For example, I have a main thread, there is created a lot of classes and etc. I have a network part, that wait for client data in separate thread. This "waiter" should run some functions from classes that was created in main thread and this functions should be executed in main thread.

How could I do so? If i call needed methods this way SomeClass::SomeMethod(some_args); from waiter, sure, they executes in secondary thread.

Would be good have something like this: SomeClass::Invoke(function_pointer); so, the function that function_pointer points on would be executed in main thread? I need an advice for windows OS.

like image 493
Kosmo零 Avatar asked Feb 12 '12 08:02

Kosmo零


3 Answers

If this is Windows Win32 application, then using the application's Message processing queue is a common approach. In the main window of your app you wait for a custom user message, typically it will be something like:

(in header file)
#define WM_MYCUSTOMMESSAGE (WM_USER + 1)

(WndProc for you main window)
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_MYCUSTOMMESSAGE:
        ... Process something
        break;
    }
}

(On seconday thread)
SendMessage(hWnd, WM_MYCUSOMMESSAGE, wParam, lParam); // Send and wait for the result

PostMessage(hWnd, WM_MYCUSTOMMESSAGE, wParam, lParam); // Send the message and continue this thread.

[EDIT] For a Console application, try using Windows Events. So create a named Event using:

(On primary thread)
HANDLE myEvent = CreateEvent(NULL, FALSE, FALSE, "MyEvent");

... later as part of a message processing loop
while(true)
{
    WaitForSingleObject( myEvent, 0 ); // Block until event is triggers in secondary thread

    ... process messages here
    ... I recommend storing "messages" in a synchronized queue
}

(On secondary thread)
SetEvent(myEvent); // Triggers the event on the main thread.
like image 135
akhisp Avatar answered Oct 31 '22 17:10

akhisp


Even with the invoke, the function would still execute in the thread it was called in, so that's of no use.

You can have a busy wait or a mutex, inside a loop, in the main thread that is released in the secondary threads, and when released, it calls some method depending on a ternary variable.

//thread1
runThread2();
while (true)
{
   mutex.acquire();
   mutex.lock();
   switch(command)
   {
      case command_noop:
         sleep(1000);
         break;
      case command1:
         foo1();
         break;
      case command2:
         foo2();
         break;
      //and so on...
   }
   mutex.release();
}

//thread2:
mutex.lock();
//commands
command = 1;
mutex.release();
mutex.acquire();
//rest of commands
like image 37
Luchian Grigore Avatar answered Oct 31 '22 18:10

Luchian Grigore


In Embarcadero C++ Builder, there are functions TThread::Queue and TThread::Synchronize, which can be used to execute functions in the main thread. This works from any thread, it doesn't have to be a TThread.

#include <vcl.h>
#include <functional>

namespace {

class wrapper : public TCppInterfacedObject<TThreadProcedure> {
public:
    wrapper(std::function<void(void)> f) : f_(f) {}

    void __fastcall Invoke() {
        f_();
    }
private:
    std::function<void(void)> f_;
};

const unsigned int main_thread = GetCurrentThreadId();

} // namespace


// Execute the function asynchronously in main thread
void queue_to_main_thread(std::function<void(void)> f)
{
    if (GetCurrentThreadId() == main_thread) {
        f();
    }
    else {
        TThread::Queue(NULL, _di_TThreadProcedure(new wrapper(f)));
    }
}

// Execute the function synchronously in main thread
void synchronize_to_main_thread(std::function<void(void)> f)
{
    if (GetCurrentThreadId() == main_thread) {
        f();
    }
    else {
        TThread::Synchronize(NULL, _di_TThreadProcedure(new wrapper(f)));
    }
}
like image 45
VLL Avatar answered Oct 31 '22 19:10

VLL