一、基本概念
C#(C Sharp)线程技术用于实现多线程编程,以便在程序中同时执行多个任务。C#提供了丰富的线程库和相关功能,可以轻松地管理多线程应用程序。涉及C#线程技术的相关内容:
- Thread 类: C#的System.Threading命名空间中提供了Thread类,用于创建和管理线程。通过Thread类,您可以创建新的线程,设置线程的优先级、状态等属性,以及控制线程的启动和终止。
- ThreadStart 委托: 使用ThreadStart委托来指定线程应该执行的方法。这个方法将在新线程中执行。
- Lambda 表达式: 您可以使用Lambda表达式来定义线程执行的代码块,这样可以更简洁地指定线程的操作。
- 线程同步: 多线程应用程序可能涉及到共享资源的并发访问,这可能导致数据竞争和错误。C#提供了锁、互斥体、信号量等线程同步机制,以确保线程安全性。
- Task 和 Task Parallel Library(TPL): .NET Framework引入了Task类和TPL,使得编写异步和并行代码更加容易。Task可以表示一个异步操作,TPL提供了更高级的并行编程模型。
- async/await 关键字: C# 5.0 引入了async和await关键字,使得异步编程变得更加直观。您可以使用它们来编写非阻塞的异步代码。
- 线程池: C#中的线程池允许您从线程池中获取可用的线程,从而避免频繁地创建和销毁线程,提高效率。
- 取消线程: C#允许您在执行中的线程中安全地取消操作,以便控制线程的执行。
- 线程安全集合: C#提供了一系列线程安全的集合,如ConcurrentQueue、ConcurrentDictionary等,用于在多线程环境中安全地操作数据。
- 线程异常处理: 您可以捕获并处理线程中的异常,以保证程序的稳定性。
在使用C#进行多线程编程时,需要仔细考虑线程安全性、资源竞争等问题,并选择适当的线程技术来满足应用程序的需求。
二、Task类的使用
Task类是C#中用于处理并发编程和异步操作的一个重要工具,使得管理并行任务和异步操作更加简便。
- 等待任务完成: 使用Task.Wait或Task.WaitAll方法来等待一个或多个任务完成。这会阻塞当前线程,直到任务完成。
- 异步操作: 使用Task.Run或Task.Factory.StartNew方法来执行异步操作。在异步方法中,可以使用async/await关键字来使代码更具可读性。
- 任务连续: 使用ContinueWith方法来定义在任务完成后要执行的操作,或使用await关键字在异步方法中实现任务连续。
- 任务取消: 使用CancellationToken来取消任务。可以在任务中轮询CancellationToken.IsCancellationRequested属性,或使用CancellationToken.ThrowIfCancellationRequested()来检查取消请求。
- 任务异常处理: 使用Task.Exception属性来检查任务是否抛出了异常,或使用Try-Catch块来处理异常。
- 任务状态: 使用Task.Status属性来获取任务的当前状态,如Running、WaitingToRun、Canceled等。
以下是一个使用Task类执行异步操作的示例,计算两个数字的和:
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 使用async/await创建异步方法
int result = await CalculateSumAsync(5, 10);
Console.WriteLine(#34;计算结果:{result}");
}
static async Task<int> CalculateSumAsync(int a, int b)
{
// 使用Task.Run创建异步操作
int sum = await Task.Run(() =>
{
int result = a + b;
return result;
});
return sum;
}
}
示例中,创建了一个异步方法CalculateSumAsync,其中使用了Task.Run来执行计算操作。在Main方法中,使用await关键字等待异步方法完成,并输出计算结果。
三、几个多场景案例
使用Task类的更多示例,涵盖了不同的场景和用法:
示例1:并行执行任务
使用Parallel.Invoke同时启动多个任务。
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Parallel.Invoke(
() => DoWork("Task 1"),
() => DoWork("Task 2"),
() => DoWork("Task 3")
);
}
static void DoWork(string taskName)
{
Console.WriteLine(#34;Starting {taskName}");
Task.Delay(1000).Wait(); // 模拟耗时操作
Console.WriteLine(#34;{taskName} completed");
}
}
示例2:连续执行任务
任务1执行完后,任务2会连续执行。
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
await Task.Run(() => Console.WriteLine("Task 1"))
.ContinueWith(task => Console.WriteLine("Task 2"));
}
}
示例3:任务取消
使用CancellationToken来取消任务。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
Task longRunningTask = Task.Run(() =>
{
Console.WriteLine("Long running task started...");
Thread.Sleep(3000);
Console.WriteLine("Long running task completed...");
}, cts.Token);
await Task.Delay(1000); // 假设在1秒后需要取消任务
cts.Cancel();
try
{
await longRunningTask;
}
catch (TaskCanceledException)
{
Console.WriteLine("Task was canceled.");
}
}
}
四、使用异步程序向多个控件添加数据
使用 C# 中的异步编程,启动多个函数,将它们的输出数据分别添加到不同的控件(如 ListView、TreeView、RichTextBox)中。
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ParallelExecutionExample
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private async void MainForm_Load(object sender, EventArgs e)
{
await RunFunctionsAndPopulateControlsAsync();
}
private async Task RunFunctionsAndPopulateControlsAsync()
{
Task[] tasks = new Task[]
{
RunFunctionAsync(AddToListView),
RunFunctionAsync(AddToTreeView),
RunFunctionAsync(AddToRichTextBox)
};
await Task.WhenAll(tasks);
}
private async Task RunFunctionAsync(Action<string> action)
{
await Task.Run(() =>
{
string output = GetFunctionOutput();
action(output);
});
}
private void AddToListView(string output)
{
if (listView1.InvokeRequired)
{
listView1.Invoke(new Action(() =>
{
ListViewItem item = new ListViewItem(output);
listView1.Items.Add(item);
}));
}
else
{
ListViewItem item = new ListViewItem(output);
listView1.Items.Add(item);
}
}
private void AddToTreeView(string output)
{
if (treeView1.InvokeRequired)
{
treeView1.Invoke(new Action(() =>
{
TreeNode node = new TreeNode(output);
treeView1.Nodes.Add(node);
}));
}
else
{
TreeNode node = new TreeNode(output);
treeView1.Nodes.Add(node);
}
}
private void AddToRichTextBox(string output)
{
if (richTextBox1.InvokeRequired)
{
richTextBox1.Invoke(new Action(() =>
{
richTextBox1.AppendText(output + Environment.NewLine);
}));
}
else
{
richTextBox1.AppendText(output + Environment.NewLine);
}
}
private string GetFunctionOutput()
{
// 模拟函数的输出
return "Function output at " + DateTime.Now.ToString("HH:mm:ss");
}
}
}
窗体加载后,使用 RunFunctionsAndPopulateControlsAsync 方法并行启动多个函数,并将它们的输出分别添加到不同的控件中。
RunFunctionAsync 方法在新线程中运行函数,然后根据不同的控件类型,调用相应的添加函数。每个添加函数在添加数据时都会判断是否需要通过 Invoke 调用来更新 UI 线程。