简体   繁体   中英

Kill a task in C#

I'm having a bit of problem dealing with an async task that generates a temperature profile.

        public static async Task genLotProfile(string lotno,string filename, string datch)
        {
            int count = 0;

            while (true)
            {
                count += 1;

                //Move this following code to new method 
                var csv = new StringBuilder();

                if (!File.Exists(filename))
                {
                    File.Create(filename); 
                }


                Tprofile temp = getLogData(datch);

                if (count == 1)
                {
                    var header = string.Format("Lotno,Temperature,Date,DataChannel");
                    csv.AppendLine(header);
                }


                var newLine = string.Format("{0},{1},{2},{3}", lotno,temp.temperature, temp.date, temp.dataChannel);

                csv.AppendLine(newLine);

                if (!File.Exists(filename))
                {
                    File.WriteAllText(filename, csv.ToString());
                }

                File.AppendAllText(filename, csv.ToString());

                //task delay
                await Task.Delay(30000);
            }
        }

And then I call it in the other form on an enter button click function.

//Temperature profile
string filename = MainWindow.getTempProfileName(MainWindow.datachannel, lotnoTBX.Text);
MainWindow.genLotProfile(lotnoTBX.Text, filename, MainWindow.datachannel);

What are the conventions of killing a task in my case?

Do not use an endless loop with await Task.Delay(30000) .

Instead, use a timer with an interval of 30 seconds. Then simply stop the timer when necessary.

In case WPF UI elemens are involved, use a DispatcherTimer. If you are using .NET Core, also use the async versions of the File methods:

private readonly DispatcherTimer timer = new DispatcherTimer
{
    Interval = TimeSpan.FromSeconds(30)
};

public MainWindow()
{
    InitializeComponent();

    timer.Tick += OnTimerTick;
    timer.Start();
}

private async void OnTimerTick(object sender, EventArgs e)
{
    ...

    if (!File.Exists(filename))
    {
        await File.WriteAllTextAsync(filename, csv.ToString());
    }
    else
    {
        await File.AppendAllTextAsync(filename, csv.ToString());
    }

    ...
}

Stop the timer at any time with

timer.Stop();

What Clemens said seems to match your use case almost perfectly, since you effectively want to have it executed every 30s and then stop on user request.

However, answering your question from another point of view, a typical way of "killing a task" is CancellationTokenSource + CancellationToken. The Token is something that works as a flag saying "die now" (starts false-ish, can be set once to true-ish state, non-clearable), and the Source is the flag's controller that allows you to raise the flag.

Mind that while that's a "standard way of cancelling task", this is NOT a way to enforce the stop. The task must periodically check that token and see if it's cancelled or not.

Now you might wonder why to have such Token at all, and why not to just use volatile/atomic/bool/etc. The answer is: CancellationToken is one-time set-only thing, it can be passed as value, merged/linked with others, subscribed to to get a callback when it is set, it has a CancellationToken.ThrowIfCancellation method that raises an exception to quickly break out of any nested if/switch/while/for - and this exception is understood by the framework and is intended to be unhandled and does not crash the process, and (...).

And most importantly, it is recognized by people. If anyone sees CancellationToken, knows that it is meant to break/stop/interrupt some processing.

Whenever you think about having a bool to stop something, use CancellationToken instead.

EDIT: I was going to write an example, but MichaelRandall beat me to it:)

The only convention is we don't abort a thread with Abort .

A sure fire way is to use a cooperative CancellationToken . This would be ideal if you need a long running task for IO work and/or UI updates. Otherwise you might as well just use a Timer as in Clemens worthy answer

public static async Task GenLotProfile(string lotno, string filename, string datchm, CancellationToken token)
{
   try
   {

      int count = 0;

      while (!token.IsCancellationRequested)
      {
         //...
         await Task.Delay(30000, token);
      }

   }
   catch (OperationCanceledException e)
   {
      // if you want to suppress the task cancelled exception that may be thrown
   }
   _logger.Debug("GenLotProfile Cancelled");
}

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