Search code examples
c#.netvmwarevmware-player

Using Delay(TimeSpan) or Thread.Sleep doesn’t properly work in VMware


I reduced my problem to this example:

[STAThread]
static void Main() {
   var t = Task.Run(async delegate {
      await Task.Delay(TimeSpan.FromSeconds(5));
      return "delayed action";
   });

   t.Wait();
   Console.WriteLine("Task t Status: {0}, Result: {1}", t.Status, t.Result);
}

While this behaves normally on my host PC, it closes before returning the "delayed action" when ran on VMware Workstation Player 15 with fresh Windows 10 installation. There are no errors. If I put another Console.WriteLine at the beginning it shows in cmd. I assigned to VMware 4 cores and 6GB of memory, cpu virtualizations are turned off, 3d acceleration is turned on. Am I missing some dependencies, or VM needs different configuration?

My goal was to create a series of SendInput functions that need to be spread over time. I even tried a 3rd party “clicker” tool that got a delay option and it has the same issue. I had to set it to 30ms to get clicks 500ms apparat, as if the bulk of clicks never registered. Doing same with my code did not work on VM but works OK on host PC.


Solution

  • I can unfortunately not help you with fixing the VMWare end, aside from two off ideas:

    • If there is anything that passes through Threads directly to the Host CPU, you could try turning them off. It would be bad for performance, but might avoid issues with the Thread (Manager) and starting OS running on slightly different clocks.

    • I do I have a different approach you could try. One that relies a whole lot less on Thread/Async and similar Delay systems. Something that might be slightly more robust, against whatever is causing this. This difference was purely by accident - it started it's live as a example for a very basic Rate Limiting System, to be run in a seperate thread:

        integer interval = 20;
        DateTime dueTime = DateTime.Now.AddMillisconds(interval);
        
        while(true){
          if(DateTime.Now >= dueTime){
            //insert code here
        
            //Update next dueTime
            dueTime = DateTime.Now.AddMillisconds(interval);
          }
          else{
            //Just yield to not tax out the CPU
            Thread.Sleep(1);
          }
        }
    

    This one only uses the Thread mechanics for the "low CPU load when idle" part. Everything else is based on the hopefully more stable DateTime System.

    Do note that short Intervalls are poorly supported, even 20 ms might already be beyond the limit. DateTime.Now() is not remotely as accurate as as the type can be precise, so it only remotely works for dual or tripple digit Intervalls. Delay and Sleep do actually support Millisecond precision.