简体   繁体   中英

How to stop thread in C#(wpf)

I have wpf app. I have 3 labels, 1 button, (Start/Stop). I have databinding. My MainWindowViewModel loooks like beneath:

namespace StartStop
{
    public class MainWindowViewModel : BindableBase
    {
        private Action<Action> RunOnUI;
        CancellationTokenSource source;
        public DelegateCommand StartCommand { get; set; }
        private string startButtonText = "START";
        public string StartButtonText
        {
            get { return startButtonText; }
            set { SetProperty(ref startButtonText, value); }
        }
        private string loop1Value ;
        public string Loop1Value
        {
            get { return loop1Value; }
            set { SetProperty(ref loop1Value, value); }
        }
        private string loop2Value;
        public string Loop2Value
        {
            get { return loop2Value; }
            set { SetProperty(ref loop2Value, value); }
        }
        private string loop3Value;
        public string Loop3Value
        {
            get { return loop3Value; }
            set { SetProperty(ref loop3Value, value); }
        }
        public MainWindowViewModel(Action<Action> runOnUI)
        {
            RunOnUI = runOnUI;
            StartCommand = new DelegateCommand(MainHandler);
        }

        async void MainHandler()
        {
            if (StartButtonText == "START")
            {
                StartButtonText = "STOP";

                try
                {
                    source = new CancellationTokenSource();
                    await Task.Run((Action)Loop1);
                }
                catch (OperationCanceledException)
                {
                    MessageBox.Show("Test was aborted by user");
                }
                finally
                {
                    StartButtonText = "START";
                    source = null;
                }
            }
            else
            {
                source = null;
                StartButtonText = "START";
            }
        }

        private void Loop1()
        {
            for(int i=0;i<100;i++)
            {
                Loop1Value = "Loop1: " + i.ToString();
                Sleep(1000, source.Token);
                Loop2();
            }
        }

        private void Loop2()
        {
            for (int i = 0; i < 100; i++)
            {
                Loop2Value = "Loop2: " + i.ToString();
                Sleep(1000, source.Token);
                Loop3();
            }
        }

        private void Loop3()
        {
            for (int i = 0; i < 100; i++)
            {
                Loop3Value = "Loop3: " + i.ToString();
                Sleep(1000, source.Token);
            }
        }
        private static void Sleep(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            Task.WaitAny(Task.Delay(millisecondsTimeout, cancellationToken));
        }
    }
}

Normally I have more advanced code and in Loops i have serial communication (rs232), I simplified code to show my problem. When I press Stop button I want the thread stop (exit all loops). I tried to throw exception when Stop is pressed, buy setting source=null, but code doesn't go to catch. Why?

Change your loop method to

private void Loop1(CancellationToken token)
{
     for(int i=0;i<100;i++)
     {
          token.ThrowIfCancellationIsRequested();
          Loop1Value = "Loop1: " + i.ToString();
          Sleep(1000, token.Token);
          Loop2(token);
     }
}

Do the same with all other loops. Also change your code for stopping to source.Cancel()

I would assume the Thread.Sleep is a stand in for reading a serial-port. Unfortunately SerialPort.Read does not seem to provide a overload with cancellation support. I'm not really faimilliar with serial ports, so yo might want to read Async Serial Port with CancellationToken and ReadTimeout . Or search for better libraries. Or if nothing else works, set a low timeout and catch the timeout exceptions.

I would also recommend to avoid mutable shared state when dealing with multiple threads. In this case it would mean to take the cancellation token and any other inputs as method parameters, and return some result. Avoid using any mutable fields. Updating the Loop1Value from a background thread looks like a very likely bug to me.

If you do not care if the operation was canceled or completed you could instead check the IsCancellationRequested property and simply return.

I want the thread stop

You need to use cooperative cancellation . Trying to stop a thread non-cooperativly is just not a good idea. See What's wrong with using Thread.Abort() for details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM