I think the problem in this case will be that there can be various ticks in the table, but the actual tick might fall inbetween those values. Then the earlier ticks would be skipped altogether. Let's say the ticks are 1000, 1010, 1030. Then when the scheduler gets called, the actual tick at that time is 1005. That means that the thread that is supposed to wake up at tick 1000 will be skipped and it will sleep forever.
I don't expect too many threads to be created, so I don't think this area would be a bottleneck. Also, the scheduler needs to enumerate through all threads anyway so it is pretty cheap to add an additional check in that loop to see whether the thread should be woken up.
I am thinking of ways to optimize this area at a later point, so I appreciate your suggestions.
I ran into another problem with threading...
I have the main thread and 4 other threads that each outputs a console message in a loop and then Sleeps for a few hundred ms during each iteration. When each non-main thread's loop exits, it sets a flag and the main thread loops until all four flags are set.
Everything works fine when either the Debug or Release builds run in the debugger, but both the Debug and Release builds get access violations when run outside of the debugger. Obviously this makes it difficult to debug. I'm wondering whether the thread switching function is really saving enough registers. Maybe adding naked or fastcall to the function declaration/definition changes the assumptions about which registers need to be saved?
Sorry for all the posts, but...
So apparently the exception that gets thrown when running the C++ app outside of the debugger is 0x40010006, which is DBG_PRINTEXCEPTION_C. When I comment out all OutputDebugString calls, the exception is no longer thrown and the application runs without problems.
According to the MSDN documentation, if the application is run outside of the debugger, OutputDebugString will output to the system debugger. If there is no system debugger, it does nothing. Except in my case it crashes the application.
I did increase the stack size a lot to ensure it isn't running out of stack space again.
the exception that gets thrown when running the C++ app outside of the debugger is 0x40010006, which is DBG_PRINTEXCEPTION_C
Hmm, I have the feeling that Windows won't always like this stack switching business. NT's structured exception handling relies on the stack and if you switch the stack... I'm not quite sure what can happen.
I'm wondering whether the thread switching function is really saving enough registers
It should be enough unless you use SSE. A normal kernel the relise on interrupts to switch threads has no choice but to save all registers because it doesn't know which registers are used. But what you're doing here is more like cooperative multithreading and more importantly, it's all done in C. The C/C++ compiler expects that a function will preserve those 4 registers (ebp, ebx, edi, esi), all other general purpose registers can be modified by the function as needed. Also, the FPU stack is supposed to be empty when a function is called so it doesn't contain anything that needs saving.
Well so as it turns out the exception is thrown when you call OutputDebugString and there is no debugger available. This is not what the MSDN documentation says (it says the call does nothing), but this is actually used by hackers to test whether their malware is running under a debugger or not. If a debugger is present, no exception would be cought and they would exit in order to prevent reverse engineering.
Doing the following solved the problem:
Now the context switching works flawlessly.
Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.