C# WhenAny Cancel call not working causing thread accumulationIs the C# static constructor thread safe?Calling the base constructor in C#C# Events and Thread SafetyHow to call asynchronous method from synchronous method in C#?The calling thread cannot access this object because a different thread owns itThe application may be doing too much work on its main threadCancellation token and thread not workingRefresh a web picture every n-seconds in a Windows RT appNavigate to other page IocContainers and MVVM lightAzure rsaKey from KeyVaultKeyResolver is always null

What if a revenant (monster) gains fire resistance?

Strong empirical falsification of quantum mechanics based on vacuum energy density

Why is so much work done on numerical verification of the Riemann Hypothesis?

What exact color does ozone gas have?

I'm the sea and the sun

Can disgust be a key component of horror?

What happens if you are holding an Iron Flask with a demon inside and walk into an Antimagic Field?

When were female captains banned from Starfleet?

Can a Canadian Travel to the USA twice, less than 180 days each time?

Is there a way to get `mathscr' with lower case letters in pdfLaTeX?

Mimic lecturing on blackboard, facing audience

Why should universal income be universal?

Why is the "ls" command showing permissions of files in a FAT32 partition?

Can I still be respawned if I die by falling off the map?

Why does AES have exactly 10 rounds for a 128-bit key, 12 for 192 bits and 14 for a 256-bit key size?

Keeping a ball lost forever

The probability of Bus A arriving before Bus B

Terse Method to Swap Lowest for Highest?

Why is this estimator biased?

How to cover method return statement in Apex Class?

What are the advantages of simplicial model categories over non-simplicial ones?

Using substitution ciphers to generate new alphabets in a novel

How to hide some fields of struct in C?

Can a College of Swords bard use a Blade Flourish option on an opportunity attack provoked by their own Dissonant Whispers spell?



C# WhenAny Cancel call not working causing thread accumulation


Is the C# static constructor thread safe?Calling the base constructor in C#C# Events and Thread SafetyHow to call asynchronous method from synchronous method in C#?The calling thread cannot access this object because a different thread owns itThe application may be doing too much work on its main threadCancellation token and thread not workingRefresh a web picture every n-seconds in a Windows RT appNavigate to other page IocContainers and MVVM lightAzure rsaKey from KeyVaultKeyResolver is always null













1















It's most likely a really stupid mistake but I cannot figure this out and I've spent almost 2 days on this.
I have an app that with a button click launches 5 tasks running in parallel but each with its own delay. This part works fine.
However, if you click the same button again, it doesn't cancel previously launched tasks and creates another instance. So basically creates more and more tasks that run in parallel. I obviously have code trying to cancel tasks if the button is clicked more than once but for some reason it doesn't work.
Could someone point me to my issue? Or is this code is beyond repair and needs total revamp? Thank you!
If you execute this WPF app and click on the button, you will see that ping frequency just keeps on increasing.



using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace TestMultiThreadWithDiffSleeps

public partial class MainWindow : Window, INotifyPropertyChanged

#region Binding
private string m_output0;
public string Output0

get return m_output0;
set m_output0 = value; OnPropertyChanged();


private string m_output1;
public string Output1

get return m_output1;
set m_output1 = value; OnPropertyChanged();


private string m_output2;
public string Output2

get return m_output2;
set m_output2 = value; OnPropertyChanged();


private string m_output3;
public string Output3

get return m_output3;
set m_output3 = value; OnPropertyChanged();


private string m_output4;
public string Output4

get return m_output4;
set m_output4 = value; OnPropertyChanged();


public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));

#endregion

private static SemaphoreSlim ThreadSemaphore;
private CancellationTokenSource CancellationTokenSrc;

public MainWindow()

InitializeComponent();
DataContext = this;
ThreadSemaphore = new SemaphoreSlim(1, 1);


private async void ButtonStart_Click(object sender, RoutedEventArgs e)

await StartToMonitor();


private async Task<bool> StartToMonitor()

M_Stop(); // Stop everything in case this is a restart

CancellationTokenSrc = new CancellationTokenSource();
bool taskResult = await M_Start();
CancellationTokenSrc = null;

return taskResult;


public void M_Stop()

Output0 = string.Empty;
Output1 = string.Empty;
Output2 = string.Empty;
Output3 = string.Empty;
Output4 = string.Empty;

if (CancellationTokenSrc != null)
CancellationTokenSrc.Cancel();


private async Task<bool> M_Start()

List<Task<bool>> tasks = new List<Task<bool>>();

// Build task list
for (int i = 0; i < 5; i++)

int iIdx = i; // Need to do this when multi-threading
int sleepTime = (i + 1) * 1000;

tasks.Add(Task.Run(async () =>

while (!CancellationTokenSrc.Token.IsCancellationRequested)

if (!Ping(iIdx))
return false; // Ping in this example always returns 'true' but you can imagine in real life there'd be 'false' returns that shall cancel all threads

await Task.Delay(sleepTime); // Delay for different length of time for each thread

return true;
, CancellationTokenSrc.Token));


Task<bool> firstFinishedTask = await Task.WhenAny(tasks);
bool result = firstFinishedTask.Result;
CancellationTokenSrc.Cancel(); // Cancel all other threads as soon as one returns

return result;


private bool Ping(int index)

ThreadSemaphore.Wait(); // Not needed for this app... here only because it's in my other app I'm troubleshooting

switch (index)

case 0: Output0 += "*"; break;
case 1: Output1 += "*"; break;
case 2: Output2 += "*"; break;
case 3: Output3 += "*"; break;
case 4: Output4 += "*"; break;


ThreadSemaphore.Release();

return true;





<Window x:Class="TestMultiThreadWithDiffSleeps.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" SizeToContent="WidthAndHeight">
<StackPanel>
<Button Content="Start" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Margin="0,30,0,0" Click="ButtonStart_Click"/>
<TextBox Text="Binding Output0"/>
<TextBox Text="Binding Output1"/>
<TextBox Text="Binding Output2"/>
<TextBox Text="Binding Output3"/>
<TextBox Text="Binding Output4"/>
</StackPanel>
</Window>









share|improve this question


























    1















    It's most likely a really stupid mistake but I cannot figure this out and I've spent almost 2 days on this.
    I have an app that with a button click launches 5 tasks running in parallel but each with its own delay. This part works fine.
    However, if you click the same button again, it doesn't cancel previously launched tasks and creates another instance. So basically creates more and more tasks that run in parallel. I obviously have code trying to cancel tasks if the button is clicked more than once but for some reason it doesn't work.
    Could someone point me to my issue? Or is this code is beyond repair and needs total revamp? Thank you!
    If you execute this WPF app and click on the button, you will see that ping frequency just keeps on increasing.



    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;

    namespace TestMultiThreadWithDiffSleeps

    public partial class MainWindow : Window, INotifyPropertyChanged

    #region Binding
    private string m_output0;
    public string Output0

    get return m_output0;
    set m_output0 = value; OnPropertyChanged();


    private string m_output1;
    public string Output1

    get return m_output1;
    set m_output1 = value; OnPropertyChanged();


    private string m_output2;
    public string Output2

    get return m_output2;
    set m_output2 = value; OnPropertyChanged();


    private string m_output3;
    public string Output3

    get return m_output3;
    set m_output3 = value; OnPropertyChanged();


    private string m_output4;
    public string Output4

    get return m_output4;
    set m_output4 = value; OnPropertyChanged();


    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

    if (PropertyChanged != null)
    PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));

    #endregion

    private static SemaphoreSlim ThreadSemaphore;
    private CancellationTokenSource CancellationTokenSrc;

    public MainWindow()

    InitializeComponent();
    DataContext = this;
    ThreadSemaphore = new SemaphoreSlim(1, 1);


    private async void ButtonStart_Click(object sender, RoutedEventArgs e)

    await StartToMonitor();


    private async Task<bool> StartToMonitor()

    M_Stop(); // Stop everything in case this is a restart

    CancellationTokenSrc = new CancellationTokenSource();
    bool taskResult = await M_Start();
    CancellationTokenSrc = null;

    return taskResult;


    public void M_Stop()

    Output0 = string.Empty;
    Output1 = string.Empty;
    Output2 = string.Empty;
    Output3 = string.Empty;
    Output4 = string.Empty;

    if (CancellationTokenSrc != null)
    CancellationTokenSrc.Cancel();


    private async Task<bool> M_Start()

    List<Task<bool>> tasks = new List<Task<bool>>();

    // Build task list
    for (int i = 0; i < 5; i++)

    int iIdx = i; // Need to do this when multi-threading
    int sleepTime = (i + 1) * 1000;

    tasks.Add(Task.Run(async () =>

    while (!CancellationTokenSrc.Token.IsCancellationRequested)

    if (!Ping(iIdx))
    return false; // Ping in this example always returns 'true' but you can imagine in real life there'd be 'false' returns that shall cancel all threads

    await Task.Delay(sleepTime); // Delay for different length of time for each thread

    return true;
    , CancellationTokenSrc.Token));


    Task<bool> firstFinishedTask = await Task.WhenAny(tasks);
    bool result = firstFinishedTask.Result;
    CancellationTokenSrc.Cancel(); // Cancel all other threads as soon as one returns

    return result;


    private bool Ping(int index)

    ThreadSemaphore.Wait(); // Not needed for this app... here only because it's in my other app I'm troubleshooting

    switch (index)

    case 0: Output0 += "*"; break;
    case 1: Output1 += "*"; break;
    case 2: Output2 += "*"; break;
    case 3: Output3 += "*"; break;
    case 4: Output4 += "*"; break;


    ThreadSemaphore.Release();

    return true;





    <Window x:Class="TestMultiThreadWithDiffSleeps.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="MainWindow" SizeToContent="WidthAndHeight">
    <StackPanel>
    <Button Content="Start" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Margin="0,30,0,0" Click="ButtonStart_Click"/>
    <TextBox Text="Binding Output0"/>
    <TextBox Text="Binding Output1"/>
    <TextBox Text="Binding Output2"/>
    <TextBox Text="Binding Output3"/>
    <TextBox Text="Binding Output4"/>
    </StackPanel>
    </Window>









    share|improve this question
























      1












      1








      1


      0






      It's most likely a really stupid mistake but I cannot figure this out and I've spent almost 2 days on this.
      I have an app that with a button click launches 5 tasks running in parallel but each with its own delay. This part works fine.
      However, if you click the same button again, it doesn't cancel previously launched tasks and creates another instance. So basically creates more and more tasks that run in parallel. I obviously have code trying to cancel tasks if the button is clicked more than once but for some reason it doesn't work.
      Could someone point me to my issue? Or is this code is beyond repair and needs total revamp? Thank you!
      If you execute this WPF app and click on the button, you will see that ping frequency just keeps on increasing.



      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Runtime.CompilerServices;
      using System.Threading;
      using System.Threading.Tasks;
      using System.Windows;

      namespace TestMultiThreadWithDiffSleeps

      public partial class MainWindow : Window, INotifyPropertyChanged

      #region Binding
      private string m_output0;
      public string Output0

      get return m_output0;
      set m_output0 = value; OnPropertyChanged();


      private string m_output1;
      public string Output1

      get return m_output1;
      set m_output1 = value; OnPropertyChanged();


      private string m_output2;
      public string Output2

      get return m_output2;
      set m_output2 = value; OnPropertyChanged();


      private string m_output3;
      public string Output3

      get return m_output3;
      set m_output3 = value; OnPropertyChanged();


      private string m_output4;
      public string Output4

      get return m_output4;
      set m_output4 = value; OnPropertyChanged();


      public event PropertyChangedEventHandler PropertyChanged;
      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

      if (PropertyChanged != null)
      PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));

      #endregion

      private static SemaphoreSlim ThreadSemaphore;
      private CancellationTokenSource CancellationTokenSrc;

      public MainWindow()

      InitializeComponent();
      DataContext = this;
      ThreadSemaphore = new SemaphoreSlim(1, 1);


      private async void ButtonStart_Click(object sender, RoutedEventArgs e)

      await StartToMonitor();


      private async Task<bool> StartToMonitor()

      M_Stop(); // Stop everything in case this is a restart

      CancellationTokenSrc = new CancellationTokenSource();
      bool taskResult = await M_Start();
      CancellationTokenSrc = null;

      return taskResult;


      public void M_Stop()

      Output0 = string.Empty;
      Output1 = string.Empty;
      Output2 = string.Empty;
      Output3 = string.Empty;
      Output4 = string.Empty;

      if (CancellationTokenSrc != null)
      CancellationTokenSrc.Cancel();


      private async Task<bool> M_Start()

      List<Task<bool>> tasks = new List<Task<bool>>();

      // Build task list
      for (int i = 0; i < 5; i++)

      int iIdx = i; // Need to do this when multi-threading
      int sleepTime = (i + 1) * 1000;

      tasks.Add(Task.Run(async () =>

      while (!CancellationTokenSrc.Token.IsCancellationRequested)

      if (!Ping(iIdx))
      return false; // Ping in this example always returns 'true' but you can imagine in real life there'd be 'false' returns that shall cancel all threads

      await Task.Delay(sleepTime); // Delay for different length of time for each thread

      return true;
      , CancellationTokenSrc.Token));


      Task<bool> firstFinishedTask = await Task.WhenAny(tasks);
      bool result = firstFinishedTask.Result;
      CancellationTokenSrc.Cancel(); // Cancel all other threads as soon as one returns

      return result;


      private bool Ping(int index)

      ThreadSemaphore.Wait(); // Not needed for this app... here only because it's in my other app I'm troubleshooting

      switch (index)

      case 0: Output0 += "*"; break;
      case 1: Output1 += "*"; break;
      case 2: Output2 += "*"; break;
      case 3: Output3 += "*"; break;
      case 4: Output4 += "*"; break;


      ThreadSemaphore.Release();

      return true;





      <Window x:Class="TestMultiThreadWithDiffSleeps.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d"
      Title="MainWindow" SizeToContent="WidthAndHeight">
      <StackPanel>
      <Button Content="Start" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Margin="0,30,0,0" Click="ButtonStart_Click"/>
      <TextBox Text="Binding Output0"/>
      <TextBox Text="Binding Output1"/>
      <TextBox Text="Binding Output2"/>
      <TextBox Text="Binding Output3"/>
      <TextBox Text="Binding Output4"/>
      </StackPanel>
      </Window>









      share|improve this question














      It's most likely a really stupid mistake but I cannot figure this out and I've spent almost 2 days on this.
      I have an app that with a button click launches 5 tasks running in parallel but each with its own delay. This part works fine.
      However, if you click the same button again, it doesn't cancel previously launched tasks and creates another instance. So basically creates more and more tasks that run in parallel. I obviously have code trying to cancel tasks if the button is clicked more than once but for some reason it doesn't work.
      Could someone point me to my issue? Or is this code is beyond repair and needs total revamp? Thank you!
      If you execute this WPF app and click on the button, you will see that ping frequency just keeps on increasing.



      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Runtime.CompilerServices;
      using System.Threading;
      using System.Threading.Tasks;
      using System.Windows;

      namespace TestMultiThreadWithDiffSleeps

      public partial class MainWindow : Window, INotifyPropertyChanged

      #region Binding
      private string m_output0;
      public string Output0

      get return m_output0;
      set m_output0 = value; OnPropertyChanged();


      private string m_output1;
      public string Output1

      get return m_output1;
      set m_output1 = value; OnPropertyChanged();


      private string m_output2;
      public string Output2

      get return m_output2;
      set m_output2 = value; OnPropertyChanged();


      private string m_output3;
      public string Output3

      get return m_output3;
      set m_output3 = value; OnPropertyChanged();


      private string m_output4;
      public string Output4

      get return m_output4;
      set m_output4 = value; OnPropertyChanged();


      public event PropertyChangedEventHandler PropertyChanged;
      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

      if (PropertyChanged != null)
      PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));

      #endregion

      private static SemaphoreSlim ThreadSemaphore;
      private CancellationTokenSource CancellationTokenSrc;

      public MainWindow()

      InitializeComponent();
      DataContext = this;
      ThreadSemaphore = new SemaphoreSlim(1, 1);


      private async void ButtonStart_Click(object sender, RoutedEventArgs e)

      await StartToMonitor();


      private async Task<bool> StartToMonitor()

      M_Stop(); // Stop everything in case this is a restart

      CancellationTokenSrc = new CancellationTokenSource();
      bool taskResult = await M_Start();
      CancellationTokenSrc = null;

      return taskResult;


      public void M_Stop()

      Output0 = string.Empty;
      Output1 = string.Empty;
      Output2 = string.Empty;
      Output3 = string.Empty;
      Output4 = string.Empty;

      if (CancellationTokenSrc != null)
      CancellationTokenSrc.Cancel();


      private async Task<bool> M_Start()

      List<Task<bool>> tasks = new List<Task<bool>>();

      // Build task list
      for (int i = 0; i < 5; i++)

      int iIdx = i; // Need to do this when multi-threading
      int sleepTime = (i + 1) * 1000;

      tasks.Add(Task.Run(async () =>

      while (!CancellationTokenSrc.Token.IsCancellationRequested)

      if (!Ping(iIdx))
      return false; // Ping in this example always returns 'true' but you can imagine in real life there'd be 'false' returns that shall cancel all threads

      await Task.Delay(sleepTime); // Delay for different length of time for each thread

      return true;
      , CancellationTokenSrc.Token));


      Task<bool> firstFinishedTask = await Task.WhenAny(tasks);
      bool result = firstFinishedTask.Result;
      CancellationTokenSrc.Cancel(); // Cancel all other threads as soon as one returns

      return result;


      private bool Ping(int index)

      ThreadSemaphore.Wait(); // Not needed for this app... here only because it's in my other app I'm troubleshooting

      switch (index)

      case 0: Output0 += "*"; break;
      case 1: Output1 += "*"; break;
      case 2: Output2 += "*"; break;
      case 3: Output3 += "*"; break;
      case 4: Output4 += "*"; break;


      ThreadSemaphore.Release();

      return true;





      <Window x:Class="TestMultiThreadWithDiffSleeps.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d"
      Title="MainWindow" SizeToContent="WidthAndHeight">
      <StackPanel>
      <Button Content="Start" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Margin="0,30,0,0" Click="ButtonStart_Click"/>
      <TextBox Text="Binding Output0"/>
      <TextBox Text="Binding Output1"/>
      <TextBox Text="Binding Output2"/>
      <TextBox Text="Binding Output3"/>
      <TextBox Text="Binding Output4"/>
      </StackPanel>
      </Window>






      c# multithreading cancellation-token






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 8 at 2:30









      SYBSYB

      3918




      3918






















          2 Answers
          2






          active

          oldest

          votes


















          2














          There are a couple of issues in this code.



          The source of the problem you're describing is this:



          tasks.Add(Task.Run(async () =>
          {
          while (!CancellationTokenSrc.Token.IsCancellationRequested)


          The tasks always check the token of the current CancellationTokenSrc. So unless the cancellation happens in the exact moment between Task.Delay calls where the tasks check IsCancellationRequested, they'll just see the new, uncancelled CTS you create after a restart.



          You should pass the current CancellationToken as a method argument or store it in a local variable inside M_Start, instead of checking the shared CancellationTokenSrc field to avoid this problem.



          Slight improvement: Task.Delay also has an overload that accepts a CancellationToken. It will throw a TaskCanceledException.



          Additionally, you're updating the OutputX properties from parallel threads (Task.Run), which then raise the PropertyChanged event that's supposed to update the UI. This kind of cross-thread UI interaction isn't safe, you will need to involve the Dispatcher to make sure the event is raised on the UI thread.



          Lastly, the ownership of CancellationTokenSrc is fairly complex and seems ripe for race conditions as multiple concurrent methods use and set it. In case of a restart M_Start could easily cause a NullReferenceException when it tries to cancel CancellationTokenSrc which has already been set to null in StartToMonitor.






          share|improve this answer























          • Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

            – SYB
            Mar 8 at 11:47



















          1














          I think you need to make Task.Delay cancellable too:



          await Task.Delay(sleepTime);



          Change it to:



          await Task.Delay(sleepTime, CancellationTokenSrc.Token);






          share|improve this answer






















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55055876%2fc-sharp-whenany-cancel-call-not-working-causing-thread-accumulation%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2














            There are a couple of issues in this code.



            The source of the problem you're describing is this:



            tasks.Add(Task.Run(async () =>
            {
            while (!CancellationTokenSrc.Token.IsCancellationRequested)


            The tasks always check the token of the current CancellationTokenSrc. So unless the cancellation happens in the exact moment between Task.Delay calls where the tasks check IsCancellationRequested, they'll just see the new, uncancelled CTS you create after a restart.



            You should pass the current CancellationToken as a method argument or store it in a local variable inside M_Start, instead of checking the shared CancellationTokenSrc field to avoid this problem.



            Slight improvement: Task.Delay also has an overload that accepts a CancellationToken. It will throw a TaskCanceledException.



            Additionally, you're updating the OutputX properties from parallel threads (Task.Run), which then raise the PropertyChanged event that's supposed to update the UI. This kind of cross-thread UI interaction isn't safe, you will need to involve the Dispatcher to make sure the event is raised on the UI thread.



            Lastly, the ownership of CancellationTokenSrc is fairly complex and seems ripe for race conditions as multiple concurrent methods use and set it. In case of a restart M_Start could easily cause a NullReferenceException when it tries to cancel CancellationTokenSrc which has already been set to null in StartToMonitor.






            share|improve this answer























            • Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

              – SYB
              Mar 8 at 11:47
















            2














            There are a couple of issues in this code.



            The source of the problem you're describing is this:



            tasks.Add(Task.Run(async () =>
            {
            while (!CancellationTokenSrc.Token.IsCancellationRequested)


            The tasks always check the token of the current CancellationTokenSrc. So unless the cancellation happens in the exact moment between Task.Delay calls where the tasks check IsCancellationRequested, they'll just see the new, uncancelled CTS you create after a restart.



            You should pass the current CancellationToken as a method argument or store it in a local variable inside M_Start, instead of checking the shared CancellationTokenSrc field to avoid this problem.



            Slight improvement: Task.Delay also has an overload that accepts a CancellationToken. It will throw a TaskCanceledException.



            Additionally, you're updating the OutputX properties from parallel threads (Task.Run), which then raise the PropertyChanged event that's supposed to update the UI. This kind of cross-thread UI interaction isn't safe, you will need to involve the Dispatcher to make sure the event is raised on the UI thread.



            Lastly, the ownership of CancellationTokenSrc is fairly complex and seems ripe for race conditions as multiple concurrent methods use and set it. In case of a restart M_Start could easily cause a NullReferenceException when it tries to cancel CancellationTokenSrc which has already been set to null in StartToMonitor.






            share|improve this answer























            • Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

              – SYB
              Mar 8 at 11:47














            2












            2








            2







            There are a couple of issues in this code.



            The source of the problem you're describing is this:



            tasks.Add(Task.Run(async () =>
            {
            while (!CancellationTokenSrc.Token.IsCancellationRequested)


            The tasks always check the token of the current CancellationTokenSrc. So unless the cancellation happens in the exact moment between Task.Delay calls where the tasks check IsCancellationRequested, they'll just see the new, uncancelled CTS you create after a restart.



            You should pass the current CancellationToken as a method argument or store it in a local variable inside M_Start, instead of checking the shared CancellationTokenSrc field to avoid this problem.



            Slight improvement: Task.Delay also has an overload that accepts a CancellationToken. It will throw a TaskCanceledException.



            Additionally, you're updating the OutputX properties from parallel threads (Task.Run), which then raise the PropertyChanged event that's supposed to update the UI. This kind of cross-thread UI interaction isn't safe, you will need to involve the Dispatcher to make sure the event is raised on the UI thread.



            Lastly, the ownership of CancellationTokenSrc is fairly complex and seems ripe for race conditions as multiple concurrent methods use and set it. In case of a restart M_Start could easily cause a NullReferenceException when it tries to cancel CancellationTokenSrc which has already been set to null in StartToMonitor.






            share|improve this answer













            There are a couple of issues in this code.



            The source of the problem you're describing is this:



            tasks.Add(Task.Run(async () =>
            {
            while (!CancellationTokenSrc.Token.IsCancellationRequested)


            The tasks always check the token of the current CancellationTokenSrc. So unless the cancellation happens in the exact moment between Task.Delay calls where the tasks check IsCancellationRequested, they'll just see the new, uncancelled CTS you create after a restart.



            You should pass the current CancellationToken as a method argument or store it in a local variable inside M_Start, instead of checking the shared CancellationTokenSrc field to avoid this problem.



            Slight improvement: Task.Delay also has an overload that accepts a CancellationToken. It will throw a TaskCanceledException.



            Additionally, you're updating the OutputX properties from parallel threads (Task.Run), which then raise the PropertyChanged event that's supposed to update the UI. This kind of cross-thread UI interaction isn't safe, you will need to involve the Dispatcher to make sure the event is raised on the UI thread.



            Lastly, the ownership of CancellationTokenSrc is fairly complex and seems ripe for race conditions as multiple concurrent methods use and set it. In case of a restart M_Start could easily cause a NullReferenceException when it tries to cancel CancellationTokenSrc which has already been set to null in StartToMonitor.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Mar 8 at 4:14









            kalimagkalimag

            60718




            60718












            • Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

              – SYB
              Mar 8 at 11:47


















            • Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

              – SYB
              Mar 8 at 11:47

















            Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

            – SYB
            Mar 8 at 11:47






            Thank you for all the tips. I implemented your recommendations with passing the the token and adding token to Task.Delay and now I get an "A task was canceled" exception on Task<bool> firstFinishedTask = await Task.WhenAny(tasks); line on the second button click.

            – SYB
            Mar 8 at 11:47














            1














            I think you need to make Task.Delay cancellable too:



            await Task.Delay(sleepTime);



            Change it to:



            await Task.Delay(sleepTime, CancellationTokenSrc.Token);






            share|improve this answer



























              1














              I think you need to make Task.Delay cancellable too:



              await Task.Delay(sleepTime);



              Change it to:



              await Task.Delay(sleepTime, CancellationTokenSrc.Token);






              share|improve this answer

























                1












                1








                1







                I think you need to make Task.Delay cancellable too:



                await Task.Delay(sleepTime);



                Change it to:



                await Task.Delay(sleepTime, CancellationTokenSrc.Token);






                share|improve this answer













                I think you need to make Task.Delay cancellable too:



                await Task.Delay(sleepTime);



                Change it to:



                await Task.Delay(sleepTime, CancellationTokenSrc.Token);







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Mar 8 at 2:43









                IlianIlian

                4,10112638




                4,10112638



























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55055876%2fc-sharp-whenany-cancel-call-not-working-causing-thread-accumulation%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme

                    Identity Server 4 is not redirecting to Angular app after login2019 Community Moderator ElectionIdentity Server 4 and dockerIdentityserver implicit flow unauthorized_clientIdentityServer Hybrid Flow - Access Token is null after user successful loginIdentity Server to MVC client : Page Redirect After loginLogin with Steam OpenId(oidc-client-js)Identity Server 4+.NET Core 2.0 + IdentityIdentityServer4 post-login redirect not working in Edge browserCall to IdentityServer4 generates System.NullReferenceException: Object reference not set to an instance of an objectIdentityServer4 without HTTPS not workingHow to get Authorization code from identity server without login form

                    2005 Ahvaz unrest Contents Background Causes Casualties Aftermath See also References Navigation menue"At Least 10 Are Killed by Bombs in Iran""Iran"Archived"Arab-Iranians in Iran to make April 15 'Day of Fury'"State of Mind, State of Order: Reactions to Ethnic Unrest in the Islamic Republic of Iran.10.1111/j.1754-9469.2008.00028.x"Iran hangs Arab separatists"Iran Overview from ArchivedConstitution of the Islamic Republic of Iran"Tehran puzzled by forged 'riots' letter""Iran and its minorities: Down in the second class""Iran: Handling Of Ahvaz Unrest Could End With Televised Confessions""Bombings Rock Iran Ahead of Election""Five die in Iran ethnic clashes""Iran: Need for restraint as anniversary of unrest in Khuzestan approaches"Archived"Iranian Sunni protesters killed in clashes with security forces"Archived