Calling a function callback on a specific known thread
-
I'm creating a synchronized queue where callers can register to have a function called after a specified timeout (or after the previous one has finished, whichever comes last). Everything works great, but I would like to extend this so that any thread can queue up items, and the callback is guaranteed to be executed on that thread. Ideally, a function like SetTimerOnThread(DWORD dwThreadID, TIMERPROC lpTimerFunc) is what I'm looking for. SetTimer() will call back on the originating thread, but the problem is that after it returns from the callback I need to set the timer for the next workitem, which may have been queued up from a different thread. Posting messages to various windows would help, but might get hairy. I'm trying to build this so that it doesn't depend on a windprocs having direct knowledge of the queue, or the queue having direct knowledge of windows. Another potential solution is to CoMarshalInterThreadInterfaceInStream the item when it enters the queue, and unmarshal just prior to executing it. The marshalling should take care of making sure everything happens on the right thread. I don't particularly like this solution though. It's overkill and the queue doesn't currently use COM. Any suggestions? --CoolDev :cool:
-
I'm creating a synchronized queue where callers can register to have a function called after a specified timeout (or after the previous one has finished, whichever comes last). Everything works great, but I would like to extend this so that any thread can queue up items, and the callback is guaranteed to be executed on that thread. Ideally, a function like SetTimerOnThread(DWORD dwThreadID, TIMERPROC lpTimerFunc) is what I'm looking for. SetTimer() will call back on the originating thread, but the problem is that after it returns from the callback I need to set the timer for the next workitem, which may have been queued up from a different thread. Posting messages to various windows would help, but might get hairy. I'm trying to build this so that it doesn't depend on a windprocs having direct knowledge of the queue, or the queue having direct knowledge of windows. Another potential solution is to CoMarshalInterThreadInterfaceInStream the item when it enters the queue, and unmarshal just prior to executing it. The marshalling should take care of making sure everything happens on the right thread. I don't particularly like this solution though. It's overkill and the queue doesn't currently use COM. Any suggestions? --CoolDev :cool:
the callback is guaranteed to be executed on that thread Wow, that's quite impressive requirement. What should happen if that thread is busy? Seems that you'll need some cooperation from the thread you want your callback to be executed on - for example, waiting for Win32 event when there's no work to do. When the event is in signaled state, thread picks up callback address from the queue and jumps into it. Tomasz Sowinski -- http://www.shooltz.com
-
the callback is guaranteed to be executed on that thread Wow, that's quite impressive requirement. What should happen if that thread is busy? Seems that you'll need some cooperation from the thread you want your callback to be executed on - for example, waiting for Win32 event when there's no work to do. When the event is in signaled state, thread picks up callback address from the queue and jumps into it. Tomasz Sowinski -- http://www.shooltz.com
The idea is that it's on a timer, so it happens whenever the thread gets around to handling the message. (I'm not trying to do something like QueueUserAPC() without expecting the thread to be in a waitable state!) This requires that all threads using the queue have a message pump, but that will always be the case for this application. If you do away with encapsulation and let a WndProc on each thread know about the queue, and have the queue store a handle to a window on each thread, than it would just be a matter of posting a message to the window once the timer has elapsed. If MSDN didn't explicitly disallow it I could pass an HWND who's message pump lives on another thread to SetTimer() with the expectation that it would post a WM_TIMER message to that window after the timeout. If params I sent to SetTimer() included a callback then it could call the callback without having to handle WM_TIMER in each WndProc. --CoolDev :cool:
-
The idea is that it's on a timer, so it happens whenever the thread gets around to handling the message. (I'm not trying to do something like QueueUserAPC() without expecting the thread to be in a waitable state!) This requires that all threads using the queue have a message pump, but that will always be the case for this application. If you do away with encapsulation and let a WndProc on each thread know about the queue, and have the queue store a handle to a window on each thread, than it would just be a matter of posting a message to the window once the timer has elapsed. If MSDN didn't explicitly disallow it I could pass an HWND who's message pump lives on another thread to SetTimer() with the expectation that it would post a WM_TIMER message to that window after the timeout. If params I sent to SetTimer() included a callback then it could call the callback without having to handle WM_TIMER in each WndProc. --CoolDev :cool:
I think you should use PostThreadMessage and place the call to message handling code inside the thread's message loop, since messages posted with PostThreadMessage have hwnd == NULL. Tomasz Sowinski -- http://www.shooltz.com