C#中多線程使用CancellationTokenSource進(jìn)行線程管理
1. Xml 代碼
<Grid Margin="15" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="120" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!-- 添加任務(wù) -->
<Label Content="Task Number" Style="{StaticResource LabelStyle}" />
<TextBox
x:Name="xTxtTaskNum"
Grid.Column="1"
Style="{StaticResource TextBoxStyle}" />
<Button
Grid.Column="3"
Click="BtnClick_CreateTasks"
Content="創(chuàng)建任務(wù)"
Style="{StaticResource BtnStyle}" />
<!-- 開(kāi)始任務(wù) -->
<Label
Grid.Row="1"
Content="Task Index"
Style="{StaticResource LabelStyle}" />
<TextBox
x:Name="xTxtStartIdx"
Grid.Row="1"
Grid.Column="1"
Style="{StaticResource TextBoxStyle}" />
<Button
Grid.Row="1"
Grid.Column="3"
Click="BtnClick_StartTask"
Content="開(kāi)始該任務(wù)"
Style="{StaticResource BtnStyle}" />
<!-- 結(jié)束任務(wù) -->
<Label
Grid.Row="2"
Content="Task Index"
Style="{StaticResource LabelStyle}" />
<TextBox
x:Name="xTxtStopIdx"
Grid.Row="2"
Grid.Column="1"
Style="{StaticResource TextBoxStyle}" />
<Button
Grid.Row="2"
Grid.Column="3"
Click="BtnClick_StopTask"
Content="停止該任務(wù)"
Style="{StaticResource BtnStyle}" />
<!-- 暫停任務(wù) -->
<Label
Grid.Row="3"
Content="Task Index"
Style="{StaticResource LabelStyle}" />
<TextBox
x:Name="xTxtPauseIdx"
Grid.Row="3"
Grid.Column="1"
Style="{StaticResource TextBoxStyle}" />
<Button
Grid.Row="3"
Grid.Column="3"
Click="BtnClick_PauseTask"
Content="暫停該任務(wù)"
Style="{StaticResource BtnStyle}" />
<!-- 恢復(fù)任務(wù) -->
<Label
Grid.Row="4"
Content="Task Index"
Style="{StaticResource LabelStyle}" />
<TextBox
x:Name="xTxtResumeIdx"
Grid.Row="4"
Grid.Column="1"
Style="{StaticResource TextBoxStyle}" />
<Button
Grid.Row="4"
Grid.Column="3"
Click="BtnClick_ResumTask"
Content="恢復(fù)該任務(wù)"
Style="{StaticResource BtnStyle}" />
</Grid>2. 代碼實(shí)現(xiàn)
public partial class TestCancellationTokenThreads : Window
{
private ConcurrentDictionary<int, TaskInfo> _dictTaskInfo = new();
private int _taskNum = 0;
public TestCancellationTokenThreads()
{
InitializeComponent();
}
private void BtnClick_CreateTasks(object sender, RoutedEventArgs e)
{
_taskNum = Convert.ToInt32(xTxtTaskNum.Text);
for (int i = 0; i < _taskNum; i++)
{
TaskInfo taskInfo = new()
{
Name = $"Task{i + 1}",
Task = null,
Cts = null,
IsPause = false,
};
_dictTaskInfo.TryAdd(i, taskInfo);
}
Debug.WriteLine($"{_taskNum}個(gè)任務(wù)創(chuàng)建成功!");
}
private void BtnClick_StartTask(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(xTxtStartIdx.Text)) return;
int idx = Convert.ToInt32(xTxtStartIdx.Text);
if (idx < 0 || idx >= _taskNum)
{
Debug.WriteLine($"任務(wù)序號(hào)超出任務(wù)總數(shù){_taskNum}");
return;
}
TaskInfo taskInfo = _dictTaskInfo[idx];
if ((taskInfo.Cts != null && !taskInfo.Cts.IsCancellationRequested) || (taskInfo.Task != null && !taskInfo.Task.IsCompleted))
{
Debug.WriteLine($"任務(wù): {taskInfo.Name}正在運(yùn)行...");
return;
}
taskInfo.Cts = new();
taskInfo.IsPause = false; //啟動(dòng)任務(wù)后,自動(dòng)開(kāi)始
Debug.WriteLine("任務(wù)開(kāi)始運(yùn)行...");
CancellationToken token = taskInfo.Cts.Token;
//創(chuàng)建任務(wù)
taskInfo.Task = Task.Run(async () =>
{
int numIdx = 0;
//執(zhí)行任務(wù)的,用 Token 的 IsCancellationRequested
while (!token.IsCancellationRequested)
{
if (!taskInfo.IsPause)
{
Debug.WriteLine(numIdx);
numIdx++;
}
try
{
await Task.Delay(1000, token);
}
catch (OperationCanceledException)
{
break; //取消則立刻退出
}
}
}, token);
}
private async void BtnClick_StopTask(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(xTxtStopIdx.Text)) return;
int idx = Convert.ToInt32(xTxtStopIdx.Text);
if (idx < 0 || idx >= _taskNum)
{
Debug.WriteLine($"任務(wù)序號(hào)超出任務(wù)總數(shù){_taskNum}");
return;
}
TaskInfo taskInfo = _dictTaskInfo[idx];
if (taskInfo.Cts == null || taskInfo.Task == null) return;
//觸發(fā)取消的操作,用 Cts 的 IsCancellationRequested
if (!taskInfo.Cts.IsCancellationRequested)
{
taskInfo.Cts.Cancel();
}
try
{
await taskInfo.Task.WaitAsync(TimeSpan.FromMilliseconds(3000));
}
catch (TimeoutException)
{
Debug.WriteLine($"任務(wù):{taskInfo.Name} 停止超時(shí)!");
}
finally
{
taskInfo.Cts.Dispose();
taskInfo.Cts = null;
taskInfo.Task = null;
}
Debug.WriteLine($"任務(wù):{taskInfo.Name} 已停止");
}
private void BtnClick_PauseTask(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(xTxtPauseIdx.Text)) return;
int idx = Convert.ToInt32(xTxtPauseIdx.Text);
if (idx < 0 || idx >= _taskNum)
{
Debug.WriteLine($"任務(wù)序號(hào)超出任務(wù)總數(shù){_taskNum}");
return;
}
TaskInfo taskInfo = _dictTaskInfo[idx];
taskInfo.IsPause = true;
}
private void BtnClick_ResumTask(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(xTxtResumeIdx.Text)) return;
int idx = Convert.ToInt32(xTxtResumeIdx.Text);
if (idx < 0 || idx >= _taskNum)
{
Debug.WriteLine($"任務(wù)序號(hào)超出任務(wù)總數(shù){_taskNum}");
return;
}
TaskInfo taskInfo = _dictTaskInfo[idx];
taskInfo.IsPause = false;
}
}
public class TaskInfo
{
public string? Name { get; set; }
public Task? Task { get; set; }
public CancellationTokenSource? Cts { get; set; }
public bool IsPause { get => _isPause; set => _isPause = value; }
public object Locker { get; set; } = new();
//以這樣的方式,保留 volatile 的功能性
//volatile: 適用于一個(gè)線程讀,一個(gè)線程寫(xiě)的情況,并且是簡(jiǎn)單類型的簡(jiǎn)單操作 (不能用于 struct等、IsPause = !IsPause 這種 "修改+寫(xiě)入"),并且只能字段
private volatile bool _isPause;
}3. 運(yùn)行

到此這篇關(guān)于C#中多線程使用CancellationTokenSource進(jìn)行線程管理的文章就介紹到這了,更多相關(guān)C# 線程管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡(jiǎn)述C#枚舉高級(jí)戰(zhàn)術(shù)
這篇文章主要介紹了簡(jiǎn)述C#枚舉高級(jí)戰(zhàn)術(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
C#實(shí)現(xiàn)排列組合算法完整實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)排列組合算法的完整實(shí)例,文中實(shí)例主要展示了排列循環(huán)方法和排列堆棧方法,需要的朋友可以參考下2014-09-09
c#使用linq技術(shù)創(chuàng)建xml文件的小例子
c#使用linq技術(shù)創(chuàng)建xml文件的小例子,需要的朋友可以參考一下2013-03-03
C#實(shí)現(xiàn)控制線程池最大數(shù)并發(fā)線程
這篇文章主要介紹了C#實(shí)現(xiàn)控制線程池最大數(shù)并發(fā)線程的相關(guān)資料,需要的朋友可以參考下2016-07-07
C#編程實(shí)現(xiàn)連接SQL SERVER數(shù)據(jù)庫(kù)實(shí)例詳解
這篇文章主要介紹了C#編程實(shí)現(xiàn)連接SQL SERVER數(shù)據(jù)庫(kù)的方法,以實(shí)例形式較為詳細(xì)的分析了C#連接SQL SERVER數(shù)據(jù)庫(kù)的相關(guān)步驟與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-11-11

