I might not have mentioned it before, but thread 'wake-up' times are approximate. For example, if you call the WaitHandle.WaitAny method with a 100ms second timeout (or call Sleep(100)), there is no guarantee that the thread will wake up in exactly 100ms. This is because of how the thread scheduler works and depends on several factors such as if there are other higher priority threads scheduled in the system (they'll run first), or other threads with equal priority (these will run with your thread in a round robin fashion).

The bottom line is your thread could wait up at very close to 100ms, but it may be some indeterminate longer time as well.

For multi-threaded programming, understanding a the details is vital. A great book to learn all this is Programming Applications for Microsoft Windows by Jeffrey Richter. The book has code samples in C++ (instead of C#), but it is excellent.