浅谈C#之线程创建和管理
一、基本介绍
线程是一种并发执行的机制,允许程序同时执行多个任务。线程的使用使得我们能够利用计算机的多核处理器,实现程序的并行执行,提高系统的性能和响应能力。本文将详细介绍C#中线程的定义和使用方法,涵盖线程的创建、启动、同步和管理等方面。
线程管理是一个重要的概念,因为多线程编程可以帮助你提高应用程序的性能,特别是在执行耗时的操作时。
二、关键点
-
线程的创建与启动:
- 使用
System.Threading.Thread
类来创建线程。你可以通过继承Thread
类并重写Run
方法,或者直接传递一个委托给Thread
类的构造函数来创建线程。 - 通过调用
Thread.Start()
方法来启动线程。
- 使用
-
线程的同步:
- 使用
lock
语句来同步对共享资源的访问,防止多个线程同时修改同一个资源。 Monitor
类提供了更高级的同步功能,如等待、通知和超时。
- 使用
-
线程池:
- 线程池是.NET Framework提供的一种机制,用于重用线程,减少创建和销毁线程的开销。
- 通过
ThreadPool.QueueUserWorkItem
方法将任务提交到线程池。
-
线程的生命周期管理:
- 线程有几种状态,如运行、等待、阻塞、死亡等。
- 可以使用
Thread.Join()
方法等待线程完成,或者使用Thread.Abort()
方法强制终止线程(不推荐,因为它可能导致资源未正确释放)。
-
线程的优先级:
- 可以通过
Thread.Priority
属性设置线程的优先级,影响线程的调度顺序。
- 可以通过
-
线程局部存储(Thread Local Storage, TLS):
- 使用
ThreadLocal<T>
类可以为每个线程存储一个独立的值,这对于避免线程间的数据共享非常有用。
- 使用
-
异步编程模型(APM)和任务并行库(TPL):
- .NET Framework提供了异步编程模型,通过
IAsyncResult
接口和回调函数来实现异步操作。 - .NET 4.0引入了任务并行库(TPL),它提供了
Task
类和Parallel
类,使得异步编程更加简单和强大。
- .NET Framework提供了异步编程模型,通过
-
CancellationToken:
- 用于在长时间运行的操作中提供取消机制,允许用户在操作完成前请求取消。
-
线程安全集合:
- .NET提供了一些线程安全的集合类,如
ConcurrentDictionary
,可以在多线程环境中安全地使用。
- .NET提供了一些线程安全的集合类,如
-
异常处理:
- 在多线程环境中,异常处理变得更加复杂,因为异常可能发生在不同的线程中。确保正确地捕获和处理线程中的异常。
三、示例代码
创建和启动线程
using System;
using System.Threading;
class Program
{
static void Main()
{
// 创建线程
Thread thread = new Thread(new ThreadStart(ThreadMethod));
thread.Start(); // 启动线程
// 等待线程完成
thread.Join();
}
static void ThreadMethod()
{
Console.WriteLine("Thread running...");
}
}
线程同步
using System;
using System.Threading;
class Program
{
static object lockObject = new object();
static int sharedResource = 0;
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(Increment));
Thread thread2 = new Thread(new ThreadStart(Increment));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Final value: {sharedResource}");
}
static void Increment()
{
for (int i = 0; i < 10000; i++)
{
lock (lockObject)
{
sharedResource++;
}
}
}
}
使用线程池
using System;
using System.Threading;
class Program
{
static void Main()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
Console.WriteLine("Main thread continues to run while work items are processed.");
}
static void DoWork(object stateInfo)
{
Console.WriteLine("Work item starting...");
Thread.Sleep(2000); // 模拟耗时操作
Console.WriteLine("Work item finishing...");
}
}
线程的生命周期管理
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread = new Thread(new ThreadStart(ThreadMethod));
thread.Start();
Console.WriteLine("Main thread waiting for thread to complete...");
thread.Join(); // 等待线程完成
Console.WriteLine("Thread has completed.");
}
static void ThreadMethod()
{
Console.WriteLine("Thread running...");
Thread.Sleep(5000); // 模拟耗时操作
}
}
线程优先级
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread = new Thread(new ThreadStart(ThreadMethod));
thread.Priority = ThreadPriority.AboveNormal;
thread.Start();
}
static void ThreadMethod()
{
Console.WriteLine("Thread running with priority: " + Thread.CurrentThread.Priority);
}
}
线程局部存储
using System;
using System.Threading;
class Program
{
static ThreadLocal<int> threadLocalValue = new ThreadLocal<int>(() => 0);
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
}
static void ThreadMethod()
{
threadLocalValue.Value++;
Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} has value: {threadLocalValue.Value}");
}
}
异步编程模型(APM)
using System;
using System.Threading;
class Program
{
static void Main()
{
AsyncResult result = new AsyncResult();
result.BeginInvoke(DoWork, result);
Console.WriteLine("Main thread continues to run...");
result.AsyncWaitHandle.WaitOne(); // 等待异步操作完成
Console.WriteLine("Work completed.");
}
static void DoWork(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
result.EndInvoke();
Console.WriteLine("Work item completed.");
}
}
public class AsyncResult : IAsyncResult
{
public object AsyncState { get; private set; }
public WaitHandle AsyncWaitHandle { get; private set; }
public bool CompletedSynchronously => false;
public bool IsCompleted { get; private set; }
public AsyncResult()
{
AsyncState = null;
AsyncWaitHandle = new ManualResetEvent(false);
}
public void BeginInvoke(Action callback, object state)
{
AsyncState = state;
ThreadPool.QueueUserWorkItem(_ =>
{
DoWork();
if (callback != null)
{
callback();
}
IsCompleted = true;
AsyncWaitHandle.Set();
});
}
public void EndInvoke()
{
AsyncWaitHandle.WaitOne();
}
private void DoWork()
{
Console.WriteLine("Work item starting...");
Thread.Sleep(2000); // 模拟耗时操作
Console.WriteLine("Work item finishing...");
}
}
任务并行库(TPL)
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
Task task1 = Task.Run(() => DoWork());
Task task2 = Task.Run(() => DoWork());
await Task.WhenAll(task1, task2);
Console.WriteLine("Main thread continues to run while tasks are processed.");
}
static void DoWork()
{
Console.WriteLine("Task starting...");
Thread.Sleep(2000); // 模拟耗时操作
Console.WriteLine("Task finishing...");
}
}
CancellationToken
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task task = Task.Run(() => DoWork(token), token);
Console.WriteLine("Press any key to cancel the task...");
Console.ReadKey();
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("Task was canceled.");
}
}
static void DoWork(CancellationToken token)
{
for (int i = 0; i < 5; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Task was canceled.");
break;
}
Console.WriteLine($"Task is running... {i}");
Thread.Sleep(1000);
}
}
}
线程安全集合
using System;
using System.Collections.Concurrent;
using System.Threading;
class Program
{
static ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(AddNumbers));
Thread thread2 = new Thread(new ThreadStart(AddNumbers));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Total numbers: {concurrentBag.Count}");
}
static void AddNumbers()
{
for (int i = 0; i < 10000; i++)
{
concurrentBag.Add(i);
}
}
}