Is it possible, after calling a boost::thread running some instructions, to come back to main thread ?
My code is based around proactor pattern, however a certain function may take some time, so in order not to block the whole program, I'm c开发者_JS百科reating a thread running this function. When this function is over, I need to call another function, but it has to be run on main thread. I have a connection pool, that is not thread safe, and I really would like to avoid mutex.
Is there a stable way to run a function on the main thread (call on another thread) ?
Just like in ObjectiveC performSelectorOnMaintThread
If you want a function to run in the main thread, you're going to have to implement some type of message-passing system. So for instance, you would launch your main thread, and then launch the worker thread. The worker thread would do it's job, while the main thread would wait for some return value from the worker thread (i.e. the main thread would be checking a message queue or something of that nature). When the worker thread finishes, it will pass into the main thread's message queue a structure (i.e., a message) with a pointer to the function it wants the main thread to run. Your messages can be pretty simple:
struct message
{
typedef void (*func_ptr)(void); //or whatever your function signature would be
func_ptr function;
bool finished;
message(): function(NULL), finished(false) {}
};
So when the worker thread is done, it will create a new message, initialize the function pointer in the message, and push that message back onto the queue that the main thread is waiting on. The main thread then reads the message off the queue, and calls the function.
BTW, and effective way to make the main thread "wait" without having to keep it in a loop and use up CPU cycles would be to use a semaphore or condition variable (like boost::condition
) between the main thread and the worker.
And one more note ... a "message queue" is simply a std::queue<message>
with appropriate locking access that the main thread reads, and the worker thread writes to. There can also be another message queue for the worker thread that the main thread writes to, and the worker thread reads if you need two-way communication between threads.
I think you might want to look into boost asio strands. They will let you specify which thread (strand) to do some wok on, and it will automatically get queued on that strand.
Note that a strand is actually more like a fiber (meaning: if there are more strands than actual threads, the strands will get multiplexed onto the available threads).
IIRC this won't however give you chance to explicitely specify the main thread1. However, more often than not this is not the actual requirement: what strands let you do easily is to make sure that operations in a strand run on the same logical thread, i.e. no concurrency is ever possible within a strand.
Trivia: Boost Asio io_service.run() is an example of a message pump
Here is the samples page for Boost Asio: http://www.boost.org/doc/libs/1_40_0/doc/html/boost_asio/examples.html
In multithreaded applications (at least for me) the main thread doesn't do much and everything is offset to other threads created at start-up. The main thread only blocks/waits (conditional variable) until instructed that we're good to exit. All work is flip/flopped between threads which makes things much easier.
And as suggest above the best way to do this is to have message queues (each queue is wrapping a worker thread or pool) and you can post messages off to one or another. With callbacks and other messaging mechanisms, you can have your "main" thread send off a message to a worker thread to do the work and provide a callback to post a message back to the "main" thread when it is done with the result. During that time, the "main" thread can continue processing other messages and actions while waiting for the result if it has any other work to do.
In case you are running in Visual Studio 2010, it should work in debug always. However, due to a bug you might need to disable and then re-enable "optimization" to make the release work.
I had a similar situation. mfc dialog with boost threads. to solve I added signals2 to the boost thread and bound them to member functions on the dialog. as the signals entered the dialog member functions I checked the thread id. if the thread id was not the same as the dialog thread id I pushed a boost function onto a std::queue of function (same signature). onidle, kickidle I check the queue and execute the functions.
精彩评论