1

I have a simple Console application with 2 running threads.

The first thread is measuring some values, and the second thread looks for user input and performs some mouse movements.

while (true)
{
    if (Input.IsKeyDown(VC_L))
    {
        Mouse.Move(300, 500);
        Thread.Sleep(thread1_delay);
        Mouse.Move(670, 300);
        Thread.Sleep(thread1_delay);
        Mouse.Move(870, 700);
        Thread.Sleep(thread1_delay);
    }
}

The problem is I want to stop the second thread as soon as I get another key as input. But it's not working since the thread is still sleeping and doesn't react.

Shivo
  • 33
  • 1
  • 6
  • 1
    One options is to use `Task.Delay`, and a `CancellationToken` – TheGeneral Feb 07 '20 at 07:55
  • 1
    If you need to cancel the sleep you should not be using Thread.Sleep, you should be using tasks and cancellation tokens. To answer your question, you can use `Thread.Interrupt` to wake it up from the current/next sleep, but this is like answering the question "How can I shoot off my food without it hurting" with "Take painkillers" – Lasse V. Karlsen Feb 07 '20 at 07:57
  • I thinks you can use Thread's Abort method – Ramil Aliyev 007 Feb 07 '20 at 07:58
  • @RamilAliyev using `Thread.Abort` to anything is almost certainly the wrong approach – TheGeneral Feb 07 '20 at 07:58
  • @MichaelRandall why? Please give me information ) – Ramil Aliyev 007 Feb 07 '20 at 07:59
  • 1
    @RamilAliyev have *Eric Lippert* instead https://stackoverflow.com/a/1560567/1612975 – TheGeneral Feb 07 '20 at 08:00
  • 1
    Thread.Interrupt and Thread.Abort is both wrong answers. The correct answer is that you shouldn't try to cancel a Thread.Sleep, instead you should use something else that can be cancelled. If you don't want/can't use tasks, use a WaitHandle, like ManualResetEvent, and wait for it with the given timeout. When the timeout occurs, the wait is over, or if you signal the handle, the wait is over. – Lasse V. Karlsen Feb 07 '20 at 08:10
  • Thread.Sleep() is not the problem, it is finite. It is `while (true)` that's the problem, that one is infinite. – Hans Passant Feb 07 '20 at 09:05
  • You are handling keyboard events and doing something in regular intervals. Maybe you should consider an event based approach (handling "OnKeyDown/Up" and "Timer_Elapsed"). – J.R. Feb 07 '20 at 19:59

2 Answers2

2

Just use a CancellationToken and be done with it

Propagates notification that operations should be canceled.

Example

public static async Task DoFunkyStuff(CancellationToken token)
{
   // a logical escape for the loop
   while (!token.IsCancellationRequested)
   {
      try
      {
         Console.WriteLine("Waiting");
         await Task.Delay(1000, token);
      }
      catch (OperationCanceledException e)
      {
         Console.WriteLine("Task Cancelled");
      }
   }
   Console.WriteLine("Finished");
}

Usage

static async Task Main(string[] args)
{

   var ts = new CancellationTokenSource();

   Console.WriteLine("Press key to cancel tasks");
   var task = DoFunkyStuff(ts.Token);

   // user input
   Console.ReadKey();

   Console.WriteLine("Cancelling token");

   // this is how to cancel
   ts.Cancel();

   // just to prove the task has been cancelled
   await task;

   // because i can
   Console.WriteLine("Elvis has left the building");
   Console.ReadKey();
}

Results

Press key to cancel tasks
Waiting
Waiting
Waiting
Waiting
Waiting
Cancelling token
Task Cancelled
Finished
Elvis has left the building
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
0

The second thread should check for a Boolean value when it wakes up. You should set this value to false when your condition is met. Now when the second thread wakes up it will complete it's execution.

Geek
  • 23,089
  • 20
  • 71
  • 85