is there any practical way around the issue of over sleeping?
Yes, run it on an Android device. (or a Linux distribution configured for the task)
The average Windows computer can run ~2-8 threads at any given time and will forcibly switch threads every 10-16ms, if your thread sleeps Windows will let something else run and it can take quite some time before it decides to run your thread again. (You might have over 300 threads active on a Windows system at any given time and while most of them are low priority background services(that won't get swapped in very often and when they do get swapped in they'll sleep very quickly again so other threads can use most of their timeslice) some of them are running at the same priority as your thread and will take as much time as they can when they get swapped in (which is what causes oversleeping).
You could also start a small c or c++ application that changes windows timeslice size using the timeBeginPeriod function, (you can push it down to 1ms if you want).
(Making the scheduler run more often will make sleep more accurate and the system more responsive but it will also reduce overall performance as the OS will spend more time swapping applications and threads in and out and less time letting them actually run. and then raise the process priority of the emulator process to high (can be done from the task manager)
On Android things are very different, the foreground application is the only high priority process and there are very few background threads running so sleep is reasonably accurate there. (Thus you don't really have to worry too much about it oversleeping in the emulator, unless it gets in the way of development)