文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
推荐链接:
开源 C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客
开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客
开源 C# .net mvc 开发(三)WEB内外网访问-CSDN博客
开源 C# .net mvc 开发(四)工程结构、页面提交以及显示-CSDN博客
开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客
开源 C# .net mvc 开发(六)发送邮件、定时以及CMD编程-CSDN博客
开源 C# .net mvc 开发(七)动态图片、动态表格和json数据生成-CSDN博客
开源 C# .net mvc 开发(八)IIS Express轻量化Web服务器的配置和使用-CSDN博客
开源 C# .net mvc 开发(九)websocket--服务器与客户端的实时通信-CSDN博客
本章节主要内容是:C#多线程编程的示例,演示了线程在不同场景下的用处和用法
在C#中,线程(Thread) 是程序执行流的最小单元,是进程中的一个独立执行路径
什么是线程?
// 线程是进程内的独立执行单元
进程 (Process) = 资源容器(内存、文件句柄等)
↓
线程 (Thread) = 实际的代码执行流(一个进程可以有多个线程)
// 比喻理解:
-
进程就像一家公司(拥有办公空间、设备等资源)
-
线程就像公司里的员工(各自执行不同的任务,共享公司资源)
线程的核心特点
❖ 共享进程的内存和资源
❖ 拥有独立的执行栈和寄存器状态
❖ 是CPU调度的基本单位
❖ 可以并发或并行执行
❖ 线程间通信比进程间通信简单高效
用途:
提高程序响应性
并行计算和性能提升
后台任务处理
目录:
1.源码分析
2.所有源码
3.效果演示
一、源码分析
Form1.cs 详细分析
- 字段和构造函数
字段声明
private static readonly object _lockObject = new object();
private static int _sharedCounter = 0;
private CancellationTokenSource _cancellationTokenSource;
private int _completedTasks = 0;
作用:
_lockObject:线程同步的锁对象
_sharedCounter:演示线程同步的共享计数器
_cancellationTokenSource:任务取消令牌源
_completedTasks:跟踪完成的任务数量
构造函数
public Form1()
{
InitializeComponent();
_cancellationTokenSource = new CancellationTokenSource();
UpdateStatus("程序已就绪");
}
作用:
调用 InitializeComponent() 初始化界面
创建取消令牌源实例
设置初始状态
- 核心演示方法
2.1 btnPerformanceTest_Click - 性能测试
private async void btnPerformanceTest_Click(object sender, EventArgs e)
{
UpdateStatus("性能测试运行中...");
AppendOutput("1. 单线程 vs 多线程性能对比");
// ... 性能测试逻辑
}
工作流程:
更新状态显示
输出测试标题
准备测试数据
分别执行单线程和多线程处理
比较并显示耗时结果
2.2 ProcessDataSingleThreaded - 单线程处理
private async Task ProcessDataSingleThreaded(int[] data)
{
await Task.Run(() =>
{
for (int i = 0; i < data.Length; i++)
{
data[i] = (int)Math.Sqrt(data[i] * Math.PI) % 1000;
}
});
}
技术要点:
使用 Task.Run 在后台线程执行以避免阻塞UI
模拟CPU密集型计算
await 确保异步完成
2.3 ProcessDataMultiThreaded - 多线程处理
private async Task ProcessDataMultiThreaded(int[] data)
{
int chunkSize = data.Length / Environment.ProcessorCount;
var tasks = new List<Task>();
for (int i = 0; i < Environment.ProcessorCount; i++)
{
int start = i * chunkSize;
int end = (i == Environment.ProcessorCount - 1) ? data.Length : start + chunkSize;
tasks.Add(Task.Run(() =>
{
for (int j = start; j < end; j++)
{
data[j] = (int)Math.Sqrt(data[j] * Math.PI) % 1000;
}
}));
}
await Task.WhenAll(tasks);
}
技术要点:
数据分块:将大数据集分成多个块
并行处理:每个块在单独的Task中处理
Task.WhenAll:等待所有任务完成
利用多核CPU优势
2.4 btnBackgroundTask_Click - 后台任务演示
private void btnBackgroundTask_Click(object sender, EventArgs e)
{
UpdateStatus("后台任务运行中...");
AppendOutput("2. 后台任务演示");
// 禁用按钮防止重复点击
btnBackgroundTask.Enabled = false;
var backgroundTask = Task.Run(async () =>
{
for (int i = 1; i <= 5; i++)
{
if (_cancellationTokenSource.Token.IsCancellationRequested)
break;
var message = $"后台任务工作: 第 {i} 次循环";
AppendOutputThreadSafe(message);
await Task.Delay(1000);
}
// ... 完成后重新启用按钮
});
}
技术要点:
按钮状态管理:防止重复提交
取消令牌检查:支持任务取消
线程安全输出:使用 AppendOutputThreadSafe
2.5 btnThreadSync_Click - 线程同步演示
private void btnThreadSync_Click(object sender, EventArgs e)
{
_sharedCounter = 0;
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
int threadNumber = i + 1;
tasks.Add(Task.Run(() => IncrementCounter(threadNumber)));
}
Task.Run(async () =>
{
await Task.WhenAll(tasks);
AppendOutputThreadSafe($"最终计数器值: {_sharedCounter} (应该是 50000)");
});
}
2.6 IncrementCounter - 计数器递增
private void IncrementCounter(int threadNumber)
{
for (int i = 0; i < 10000; i++)
{
// 使用锁确保线程安全
lock (_lockObject)
{
_sharedCounter++;
}
}
AppendOutputThreadSafe($"线程-{threadNumber} 完成工作");
}
技术要点:
lock 关键字:确保对共享资源的互斥访问
防止竞态条件
演示没有锁时会出现的数据不一致问题
2.7 btnProducerConsumer_Click - 生产者消费者模式
var producer = Task.Run(async () =>
{
for (int i = 0; i < totalItems; i++)
{
lock (_lockObject)
{
while (queue.Count >= maxSize)
{
Monitor.Wait(_lockObject); // 等待队列有空位
}
queue.Enqueue(i);
Monitor.PulseAll(_lockObject); // 通知消费者
}
await Task.Delay(100);
}
});
技术要点:
Monitor.Wait/PulseAll:线程间通信
缓冲区管理:防止队列溢出
协调生产者和消费者的速度差异
- 线程安全辅助方法
3.1 AppendOutput - 线程安全输出
private void AppendOutput(string text)
{
if (txtOutput.InvokeRequired)
{
txtOutput.Invoke(new Action<string>(AppendOutput), text);
}
else
{
txtOutput.AppendText(text + Environment.NewLine);
txtOutput.ScrollToCaret();
}
}
技术要点:
InvokeRequired:检查是否需要在UI线程执行
Control.Invoke:跨线程调用UI更新
ScrollToCaret:自动滚动到最新内容
3.2 UpdateProgressBarThreadSafe - 进度条更新
private void UpdateProgressBarThreadSafe(int value)
{
if (progressBar1.InvokeRequired)
{
progressBar1.Invoke(new Action<int>(UpdateProgressBarThreadSafe), value);
}
else
{
progressBar1.Value = Math.Min(value, progressBar1.Maximum);
lblProgress.Text = $"任务进度: {value}%";
}
}
技术要点:
进度值和标签文本同步更新
防止进度值超出范围
3.3 UpdateStatus - 状态栏更新
private void UpdateStatus(string status)
{
if (lblStatus.InvokeRequired)
{
lblStatus.Invoke(new Action<string>(UpdateStatus), status);
}
else
{
lblStatus.Text = status;
}
}
作用:提供用户友好的状态反馈。
- 任务管理方法
4.1 btnCancelTasks_Click - 取消任务
private void btnCancelTasks_Click(object sender, EventArgs e)
{
AppendOutput("取消所有任务...");
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
UpdateStatus("已发送取消请求");
btnBackgroundTask.Enabled = true;
}
技术要点:
CancellationTokenSource.Cancel():发送取消信号
创建新的令牌源:为后续任务准备
恢复按钮状态
4.2 Form1_FormClosing - 窗体关闭处理
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_cancellationTokenSource?.Cancel();
}
作用:确保程序退出时所有后台任务被正确取消。
二、所有源码
Form1.Designer.cs源码
using System.Drawing;
using System.Windows.Forms;
namespace _10_thread
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
btnPerformanceTest = new Button();
btnBackgroundTask = new Button();
btnThreadSync = new Button();
btnProducerConsumer = new Button();
btnParallelProcessing = new Button();
btnCancelTasks = new Button();
btnClear = new Button();
txtOutput = new TextBox();
progressBar1 = new ProgressBar();
lblProgress = new Label();
groupBox1 = new GroupBox();
groupBox2 = new GroupBox();
lblStatus = new Label();
groupBox1.SuspendLayout();
groupBox2.SuspendLayout();
SuspendLayout();
//
// btnPerformanceTest
//
btnPerformanceTest.BackColor = Color.LightBlue;
btnPerformanceTest.Location = new Point(16, 26);
btnPerformanceTest.Margin = new Padding(4);
btnPerformanceTest.Name = "btnPerformanceTest";
btnPerformanceTest.Size = new Size(150, 40);
btnPerformanceTest.TabIndex = 0;
btnPerformanceTest.Text = "1. 性能测试";
btnPerformanceTest.UseVisualStyleBackColor = false;
btnPerformanceTest.Click += btnPerformanceTest_Click;
//
// btnBackgroundTask
//
btnBackgroundTask.BackColor = Color.LightBlue;
btnBackgroundTask.Location = new Point(174, 26);
btnBackgroundTask.Margin = new Padding(4);
btnBackgroundTask.Name = "btnBackgroundTask";
btnBackgroundTask.Size = new Size(150, 40);
btnBackgroundTask.TabIndex = 1;
btnBackgroundTask.Text = "2. 后台任务";
btnBackgroundTask.UseVisualStyleBackColor = false;
btnBackgroundTask.Click += btnBackgroundTask_Click;
//
// btnThreadSync
//
btnThreadSync.BackColor = Color.LightBlue;
btnThreadSync.Location = new Point(332, 26);
btnThreadSync.Margin = new Padding(4);
btnThreadSync.Name = "btnThreadSync";
btnThreadSync.Size = new Size(150, 40);
btnThreadSync.TabIndex = 2;
btnThreadSync.Text = "3. 线程同步";
btnThreadSync.UseVisualStyleBackColor = false;
btnThreadSync.Click += btnThreadSync_Click;
//
// btnProducerConsumer
//
btnProducerConsumer.BackColor = Color.LightBlue;
btnProducerConsumer.Location = new Point(490, 26);
btnProducerConsumer.Margin = new Padding(4);
btnProducerConsumer.Name = "btnProducerConsumer";
btnProducerConsumer.Size = new Size(150, 40);
btnProducerConsumer.TabIndex = 3;
btnProducerConsumer.Text = "4. 生产者-消费者";
btnProducerConsumer.UseVisualStyleBackColor = false;
btnProducerConsumer.Click += btnProducerConsumer_Click;
//
// btnParallelProcessing
//
btnParallelProcessing.BackColor = Color.LightBlue;
btnParallelProcessing.Location = new Point(648, 26);
btnParallelProcessing.Margin = new Padding(4);
btnParallelProcessing.Name = "btnParallelProcessing";
btnParallelProcessing.Size = new Size(150, 40);
btnParallelProcessing.TabIndex = 4;
btnParallelProcessing.Text = "5. 并行处理";
btnParallelProcessing.UseVisualStyleBackColor = false;
btnParallelProcessing.Click += btnParallelProcessing_Click;
//
// btnCancelTasks
//
btnCancelTasks.BackColor = Color.LightCoral;
btnCancelTasks.Location = new Point(16, 85);
btnCancelTasks.Margin = new Padding(4);
btnCancelTasks.Name = "btnCancelTasks";
btnCancelTasks.Size = new Size(150, 40);
btnCancelTasks.TabIndex = 5;
btnCancelTasks.Text = "取消所有任务";
btnCancelTasks.UseVisualStyleBackColor = false;
btnCancelTasks.Click += btnCancelTasks_Click;
//
// btnClear
//
btnClear.BackColor = Color.LightGreen;
btnClear.Location = new Point(174, 85);
btnClear.Margin = new Padding(4);
btnClear.Name = "btnClear";
btnClear.Size = new Size(150, 40);
btnClear.TabIndex = 6;
btnClear.Text = "清空输出";
btnClear.UseVisualStyleBackColor = false;
btnClear.Click += btnClear_Click;
//
// txtOutput
//
txtOutput.BackColor = Color.Black;
txtOutput.Font = new Font("Consolas", 9.75F, FontStyle.Regular, GraphicsUnit.Point, 0);
txtOutput.ForeColor = Color.White;
txtOutput.Location = new Point(16, 28);
txtOutput.Margin = new Padding(4);
txtOutput.Multiline = true;
txtOutput.Name = "txtOutput";
txtOutput.ReadOnly = true;
txtOutput.ScrollBars = ScrollBars.Vertical;
txtOutput.Size = new Size(968, 438);
txtOutput.TabIndex = 7;
//
// progressBar1
//
progressBar1.Location = new Point(490, 92);
progressBar1.Margin = new Padding(4);
progressBar1.Name = "progressBar1";
progressBar1.Size = new Size(308, 27);
progressBar1.TabIndex = 8;
//
// lblProgress
//
lblProgress.AutoSize = true;
lblProgress.Location = new Point(332, 96);
lblProgress.Margin = new Padding(4, 0, 4, 0);
lblProgress.Name = "lblProgress";
lblProgress.Size = new Size(150, 20);
lblProgress.TabIndex = 9;
lblProgress.Text = "任务进度: 0%";
//
// groupBox1
//
groupBox1.Controls.Add(btnPerformanceTest);
groupBox1.Controls.Add(lblProgress);
groupBox1.Controls.Add(btnBackgroundTask);
groupBox1.Controls.Add(progressBar1);
groupBox1.Controls.Add(btnThreadSync);
groupBox1.Controls.Add(btnCancelTasks);
groupBox1.Controls.Add(btnProducerConsumer);
groupBox1.Controls.Add(btnClear);
groupBox1.Controls.Add(btnParallelProcessing);
groupBox1.Dock = DockStyle.Top;
groupBox1.Location = new Point(0, 0);
groupBox1.Margin = new Padding(4);
groupBox1.Name = "groupBox1";
groupBox1.Padding = new Padding(4);
groupBox1.Size = new Size(1000, 140);
groupBox1.TabIndex = 10;
groupBox1.TabStop = false;
groupBox1.Text = "线程演示控制";
//
// groupBox2
//
groupBox2.Controls.Add(txtOutput);
groupBox2.Dock = DockStyle.Fill;
groupBox2.Location = new Point(0, 140);
groupBox2.Margin = new Padding(4);
groupBox2.Name = "groupBox2";
groupBox2.Padding = new Padding(4);
groupBox2.Size = new Size(1000, 484);
groupBox2.TabIndex = 11;
groupBox2.TabStop = false;
groupBox2.Text = "输出信息";
//
// lblStatus
//
lblStatus.BackColor = SystemColors.Info;
lblStatus.BorderStyle = BorderStyle.FixedSingle;
lblStatus.Dock = DockStyle.Bottom;
lblStatus.Location = new Point(0, 624);
lblStatus.Margin = new Padding(4, 0, 4, 0);
lblStatus.Name = "lblStatus";
lblStatus.Size = new Size(1000, 28);
lblStatus.TabIndex = 12;
lblStatus.Text = "就绪";
lblStatus.TextAlign = ContentAlignment.MiddleLeft;
//
// Form1
//
AutoScaleDimensions = new SizeF(9F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1000, 652);
Controls.Add(groupBox2);
Controls.Add(groupBox1);
Controls.Add(lblStatus);
Margin = new Padding(4);
MinimumSize = new Size(1018, 699);
Name = "Form1";
Text = "C# 多线程演示程序";
FormClosing += Form1_FormClosing;
groupBox1.ResumeLayout(false);
groupBox1.PerformLayout();
groupBox2.ResumeLayout(false);
groupBox2.PerformLayout();
ResumeLayout(false);
}
#endregion
private Button btnPerformanceTest;
private Button btnBackgroundTask;
private Button btnThreadSync;
private Button btnProducerConsumer;
private Button btnParallelProcessing;
private Button btnCancelTasks;
private Button btnClear;
private TextBox txtOutput;
private ProgressBar progressBar1;
private Label lblProgress;
private GroupBox groupBox1;
private GroupBox groupBox2;
private Label lblStatus;
}
}
Form1.cs源码
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _10_thread
{
public partial class Form1 : Form
{
private static readonly object _lockObject = new object();
private static int _sharedCounter = 0;
private CancellationTokenSource _cancellationTokenSource;
private int _completedTasks = 0;
public Form1()
{
InitializeComponent();
_cancellationTokenSource = new CancellationTokenSource();
UpdateStatus("程序已就绪");
}
// 1. 性能对比演示
private async void btnPerformanceTest_Click(object sender, EventArgs e)
{
UpdateStatus("性能测试运行中...");
AppendOutput("1. 单线程 vs 多线程性能对比");
AppendOutput("---------------------------");
int[] data = Enumerable.Range(1, 1000000).ToArray(); // 减少数据量以适应UI演示
// 单线程处理
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
await ProcessDataSingleThreaded(data);
stopwatch.Stop();
AppendOutput($"单线程处理时间: {stopwatch.ElapsedMilliseconds} ms");
// 多线程处理
stopwatch.Restart();
await ProcessDataMultiThreaded(data);
stopwatch.Stop();
AppendOutput($"多线程处理时间: {stopwatch.ElapsedMilliseconds} ms");
AppendOutput("");
UpdateStatus("性能测试完成");
}
private async Task ProcessDataSingleThreaded(int[] data)
{
await Task.Run(() =>
{
for (int i = 0; i < data.Length; i++)
{
data[i] = (int)Math.Sqrt(data[i] * Math.PI) % 1000;
}
});
}
private async Task ProcessDataMultiThreaded(int[] data)
{
int chunkSize = data.Length / Environment.ProcessorCount;
var tasks = new List<Task>();
for (int i = 0; i < Environment.ProcessorCount; i++)
{
int start = i * chunkSize;
int end = (i == Environment.ProcessorCount - 1) ? data.Length : start + chunkSize;
tasks.Add(Task.Run(() =>
{
for (int j = start; j < end; j++)
{
data[j] = (int)Math.Sqrt(data[j] * Math.PI) % 1000;
}
}));
}
await Task.WhenAll(tasks);
}
// 2. 后台任务演示
private void btnBackgroundTask_Click(object sender, EventArgs e)
{
UpdateStatus("后台任务运行中...");
AppendOutput("2. 后台任务演示");
AppendOutput("---------------");
// 禁用按钮防止重复点击
btnBackgroundTask.Enabled = false;
// 使用 Task 创建后台任务
var backgroundTask = Task.Run(async () =>
{
for (int i = 1; i <= 5; i++)
{
if (_cancellationTokenSource.Token.IsCancellationRequested)
break;
var message = $"后台任务工作: 第 {i} 次循环";
AppendOutputThreadSafe(message);
UpdateStatus($"后台任务运行中... ({i}/5)");
await Task.Delay(1000);
}
if (!_cancellationTokenSource.Token.IsCancellationRequested)
{
AppendOutputThreadSafe("后台任务完成");
UpdateStatus("后台任务完成");
Invoke(new Action(() => btnBackgroundTask.Enabled = true));
}
});
}
// 3. 线程同步演示
private void btnThreadSync_Click(object sender, EventArgs e)
{
UpdateStatus("线程同步演示运行中...");
AppendOutput("3. 线程同步演示");
AppendOutput("---------------");
_sharedCounter = 0;
var tasks = new List<Task>();
// 创建多个任务同时访问共享资源
for (int i = 0; i < 5; i++)
{
int threadNumber = i + 1;
tasks.Add(Task.Run(() => IncrementCounter(threadNumber)));
}
// 等待所有任务完成
Task.Run(async () =>
{
await Task.WhenAll(tasks);
AppendOutputThreadSafe($"最终计数器值: {_sharedCounter} (应该是 50000)");
AppendOutputThreadSafe("");
UpdateStatus("线程同步演示完成");
});
}
private void IncrementCounter(int threadNumber)
{
for (int i = 0; i < 10000; i++)
{
// 使用锁确保线程安全
lock (_lockObject)
{
_sharedCounter++;
}
}
AppendOutputThreadSafe($"线程-{threadNumber} 完成工作");
}
// 4. 生产者-消费者模式演示
private void btnProducerConsumer_Click(object sender, EventArgs e)
{
UpdateStatus("生产者-消费者模式运行中...");
AppendOutput("4. 生产者-消费者模式演示");
AppendOutput("-----------------------");
var queue = new Queue<int>();
const int maxSize = 5;
const int totalItems = 10;
// 生产者任务
var producer = Task.Run(async () =>
{
for (int i = 0; i < totalItems; i++)
{
if (_cancellationTokenSource.Token.IsCancellationRequested)
break;
lock (_lockObject)
{
while (queue.Count >= maxSize)
{
Monitor.Wait(_lockObject);
}
queue.Enqueue(i);
AppendOutputThreadSafe($"生产者生产: {i}");
Monitor.PulseAll(_lockObject);
}
await Task.Delay(100);
}
});
// 消费者任务
var consumer = Task.Run(async () =>
{
int consumedItems = 0;
while (consumedItems < totalItems && !_cancellationTokenSource.Token.IsCancellationRequested)
{
lock (_lockObject)
{
while (queue.Count == 0 && consumedItems < totalItems)
{
Monitor.Wait(_lockObject);
}
if (queue.Count > 0)
{
int item = queue.Dequeue();
consumedItems++;
AppendOutputThreadSafe($"消费者消费: {item}");
Monitor.PulseAll(_lockObject);
}
}
await Task.Delay(150);
}
if (!_cancellationTokenSource.Token.IsCancellationRequested)
{
AppendOutputThreadSafe("生产者-消费者演示完成");
AppendOutputThreadSafe("");
UpdateStatus("生产者-消费者演示完成");
}
});
}
// 5. 并行处理演示
private void btnParallelProcessing_Click(object sender, EventArgs e)
{
UpdateStatus("并行处理运行中...");
AppendOutput("5. 并行处理演示");
AppendOutput("---------------");
var numbers = Enumerable.Range(1, 10).ToList(); // 减少数量用于演示
// 重置进度条
Invoke(new Action(() =>
{
progressBar1.Value = 0;
_completedTasks = 0;
lblProgress.Text = "任务进度: 0%";
}));
// 并行处理
Task.Run(() =>
{
AppendOutputThreadSafe("开始并行处理...");
Parallel.ForEach(numbers, new ParallelOptions { MaxDegreeOfParallelism = 3 }, number =>
{
if (_cancellationTokenSource.Token.IsCancellationRequested)
return;
ProcessNumber(number);
// 更新进度
int completed = Interlocked.Increment(ref _completedTasks);
int progress = completed * 100 / numbers.Count;
UpdateProgressBarThreadSafe(progress);
UpdateStatus($"并行处理进度: {progress}%");
});
if (!_cancellationTokenSource.Token.IsCancellationRequested)
{
AppendOutputThreadSafe("并行处理完成");
AppendOutputThreadSafe("");
UpdateStatus("并行处理完成");
}
});
}
private void ProcessNumber(int number)
{
// 模拟一些工作
Thread.Sleep(500);
AppendOutputThreadSafe($"处理数字: {number} (线程: {Thread.CurrentThread.ManagedThreadId})");
}
// 6. 取消任务演示
private void btnCancelTasks_Click(object sender, EventArgs e)
{
AppendOutput("取消所有任务...");
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource(); // 创建新的取消令牌
UpdateStatus("已发送取消请求");
// 重新启用按钮
btnBackgroundTask.Enabled = true;
}
// 7. 清空输出
private void btnClear_Click(object sender, EventArgs e)
{
txtOutput.Clear();
UpdateStatus("输出已清空");
}
// 线程安全的输出方法
private void AppendOutput(string text)
{
if (txtOutput.InvokeRequired)
{
txtOutput.Invoke(new Action<string>(AppendOutput), text);
}
else
{
txtOutput.AppendText(text + Environment.NewLine);
txtOutput.ScrollToCaret();
}
}
private void AppendOutputThreadSafe(string text)
{
AppendOutput(text);
}
private void UpdateProgressBarThreadSafe(int value)
{
if (progressBar1.InvokeRequired)
{
progressBar1.Invoke(new Action<int>(UpdateProgressBarThreadSafe), value);
}
else
{
progressBar1.Value = Math.Min(value, progressBar1.Maximum);
lblProgress.Text = $"任务进度: {value}%";
}
}
private void UpdateStatus(string status)
{
if (lblStatus.InvokeRequired)
{
lblStatus.Invoke(new Action<string>(UpdateStatus), status);
}
else
{
lblStatus.Text = status;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_cancellationTokenSource?.Cancel();
}
}
}
三、效果演示
按下并行处理,多线程运行,同时进度条开始更新。
