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
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
add a comment |
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
add a comment |
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
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
c# multithreading cancellation-token
asked Mar 8 at 2:30
SYBSYB
3918
3918
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
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
.
Thank you for all the tips. I implemented your recommendations with passing the the token and adding token toTask.Delay
and now I get an "A task was canceled" exception onTask<bool> firstFinishedTask = await Task.WhenAny(tasks);
line on the second button click.
– SYB
Mar 8 at 11:47
add a comment |
I think you need to make Task.Delay
cancellable too:
await Task.Delay(sleepTime);
Change it to:
await Task.Delay(sleepTime, CancellationTokenSrc.Token);
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
.
Thank you for all the tips. I implemented your recommendations with passing the the token and adding token toTask.Delay
and now I get an "A task was canceled" exception onTask<bool> firstFinishedTask = await Task.WhenAny(tasks);
line on the second button click.
– SYB
Mar 8 at 11:47
add a comment |
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
.
Thank you for all the tips. I implemented your recommendations with passing the the token and adding token toTask.Delay
and now I get an "A task was canceled" exception onTask<bool> firstFinishedTask = await Task.WhenAny(tasks);
line on the second button click.
– SYB
Mar 8 at 11:47
add a comment |
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
.
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
.
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 toTask.Delay
and now I get an "A task was canceled" exception onTask<bool> firstFinishedTask = await Task.WhenAny(tasks);
line on the second button click.
– SYB
Mar 8 at 11:47
add a comment |
Thank you for all the tips. I implemented your recommendations with passing the the token and adding token toTask.Delay
and now I get an "A task was canceled" exception onTask<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
add a comment |
I think you need to make Task.Delay
cancellable too:
await Task.Delay(sleepTime);
Change it to:
await Task.Delay(sleepTime, CancellationTokenSrc.Token);
add a comment |
I think you need to make Task.Delay
cancellable too:
await Task.Delay(sleepTime);
Change it to:
await Task.Delay(sleepTime, CancellationTokenSrc.Token);
add a comment |
I think you need to make Task.Delay
cancellable too:
await Task.Delay(sleepTime);
Change it to:
await Task.Delay(sleepTime, CancellationTokenSrc.Token);
I think you need to make Task.Delay
cancellable too:
await Task.Delay(sleepTime);
Change it to:
await Task.Delay(sleepTime, CancellationTokenSrc.Token);
answered Mar 8 at 2:43
IlianIlian
4,10112638
4,10112638
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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