C# 多线程编程 (.NET Framework 4.0)
C# 多线程编程 (.NET Framework 4.0)
主要章节
-
线程基础概念
- 前台线程与后台线程的区别和使用
- UI线程的特殊处理(包括Invoke和BeginInvoke)
-
线程创建和管理
- Thread类的详细使用
- ThreadPool线程池的高效管理
- BackgroundWorker用于Windows Forms
-
线程同步和保护机制
- lock语句和Monitor类
- Mutex互斥量(支持跨进程)
- Semaphore信号量(限制并发数)
- ReaderWriterLockSlim读写锁
- AutoResetEvent和ManualResetEvent事件
- Interlocked原子操作
- Barrier屏障同步
- SpinLock自旋锁
-
线程安全集合
- ConcurrentDictionary等并发集合的使用
-
最佳实践
- 死锁预防策略
- 异常处理
- 线程池配置优化
- 所有代码示例都包含完整的using语句和类定义,可以直接复制使用
- 每种机制都配有实际应用场景,帮助您选择合适的方案
- 包含常见错误示例和正确做法对比,避免踩坑
- 注重资源管理,展示了如何正确释放同步对象
根据不同场景选择合适的机制:
- 简单共享资源保护 → 使用lock
- 跨进程同步 → 使用命名Mutex
- 限制并发访问数 → 使用Semaphore
- 读多写少 → 使用ReaderWriterLockSlim
- 简单计数操作 → 使用Interlocked
- 短期任务 → 使用ThreadPool
- 长期运行任务 → 使用Thread类
一、线程基础概念
1.1 前台线程与后台线程
前台线程(Foreground Thread):
- 应用程序必须等待所有前台线程执行完毕才会退出
- 默认创建的线程都是前台线程
- 主线程默认是前台线程
后台线程(Background Thread):
- 当所有前台线程结束后,后台线程会被自动终止
- 不会阻止应用程序的退出
- 线程池中的线程都是后台线程
using System;
using System.Threading;class ForegroundBackgroundExample
{static void Main(){// 创建前台线程Thread foregroundThread = new Thread(WorkMethod);foregroundThread.Name = "前台线程";foregroundThread.IsBackground = false; // 默认就是false// 创建后台线程Thread backgroundThread = new Thread(WorkMethod);backgroundThread.Name = "后台线程";backgroundThread.IsBackground = true;foregroundThread.Start();backgroundThread.Start();Console.WriteLine("主线程结束");// 程序会等待前台线程结束,但不会等待后台线程}static void WorkMethod(){string threadType = Thread.CurrentThread.IsBackground ? "后台" : "前台";for (int i = 0; i < 5; i++){Console.WriteLine("{0}线程: {1}, 计数: {2}", threadType, Thread.CurrentThread.Name, i);Thread.Sleep(1000);}}
}
1.2 UI线程(主线程)
在Windows Forms或WPF应用中,UI线程是特殊的线程,负责处理用户界面的更新和事件。
using System;
using System.Windows.Forms;
using System.Threading;public partial class Form1 : Form
{private Button button1;private Label label1;public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){// 创建后台线程处理耗时操作Thread workerThread = new Thread(DoWork);workerThread.IsBackground = true;workerThread.Start();}private void DoWork(){// 模拟耗时操作Thread.Sleep(2000);// 错误方式:直接从后台线程访问UI控件// label1.Text = "完成"; // 这会抛出异常// 正确方式:使用Invoke或BeginInvokeif (label1.InvokeRequired){label1.Invoke(new Action(() =>{label1.Text = "操作完成";}));}else{label1.Text = "操作完成";}}// 更优雅的方式:使用扩展方法private void UpdateUI(string text){Action action = () => label1.Text = text;if (InvokeRequired)Invoke(action);elseaction();}
}
二、线程创建和管理
2.1 Thread类
Thread类提供了最直接的线程创建和控制方式。
using System;
using System.Threading;class ThreadExample
{static void Main(){// 方式1:使用ThreadStart委托(无参数)Thread thread1 = new Thread(new ThreadStart(SimpleMethod));thread1.Start();// 方式2:使用ParameterizedThreadStart委托(带参数)Thread thread2 = new Thread(new ParameterizedThreadStart(ParameterizedMethod));thread2.Start("Hello Thread");// 方式3:使用Lambda表达式Thread thread3 = new Thread(() =>{Console.WriteLine("Lambda线程执行");});thread3.Start();// 设置线程属性Thread thread4 = new Thread(DetailedMethod);thread4.Name = "工作线程";thread4.Priority = ThreadPriority.AboveNormal;thread4.IsBackground = true;thread4.Start();// 等待线程完成thread1.Join();thread2.Join();thread3.Join();thread4.Join(1000); // 最多等待1秒Console.WriteLine("所有线程执行完成");}static void SimpleMethod(){Console.WriteLine("简单方法执行,线程ID: " + Thread.CurrentThread.ManagedThreadId);}static void ParameterizedMethod(object obj){Console.WriteLine("参数化方法执行,参数: " + obj);}static void DetailedMethod(){Thread current = Thread.CurrentThread;Console.WriteLine("线程名称: {0}, ID: {1}, 优先级: {2}, 是否后台: {3}",current.Name, current.ManagedThreadId, current.Priority, current.IsBackground);}
}
2.2 ThreadPool线程池
线程池提供了更高效的线程管理方式,避免了频繁创建和销毁线程的开销。
using System;
using System.Threading;class ThreadPoolExample
{static void Main(){// 获取线程池信息int workerThreads, completionPortThreads;ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);Console.WriteLine("最大工作线程数: {0}, 最大IO线程数: {1}", workerThreads, completionPortThreads);// 方式1:使用QueueUserWorkItemThreadPool.QueueUserWorkItem(WorkItem);ThreadPool.QueueUserWorkItem(WorkItemWithState, "状态数据");// 方式2:使用WaitCallback委托WaitCallback callback = new WaitCallback(WorkItem);ThreadPool.QueueUserWorkItem(callback);// 使用ManualResetEvent等待线程池任务完成ManualResetEvent[] events = new ManualResetEvent[5];for (int i = 0; i < 5; i++){events[i] = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(state =>{int index = (int)state;Console.WriteLine("线程池任务 {0} 开始", index);Thread.Sleep(1000);Console.WriteLine("线程池任务 {0} 完成", index);events[index].Set();}, i);}// 等待所有任务完成WaitHandle.WaitAll(events);Console.WriteLine("所有线程池任务完成");// 清理资源foreach (var evt in events){evt.Dispose();}}static void WorkItem(object state){Console.WriteLine("线程池工作项执行,线程ID: {0}, 是否线程池线程: {1}",Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread);}static void WorkItemWithState(object state){Console.WriteLine("带状态的工作项,状态: {0}", state);}
}
2.3 BackgroundWorker(适用于Windows Forms)
BackgroundWorker专门用于Windows Forms应用中的后台操作。
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;public partial class BackgroundWorkerForm : Form
{private BackgroundWorker backgroundWorker;private Button startButton;private ProgressBar progressBar;private Label statusLabel;public BackgroundWorkerForm(){InitializeComponent();InitializeBackgroundWorker();}private void InitializeBackgroundWorker(){backgroundWorker = new BackgroundWorker();backgroundWorker.WorkerReportsProgress = true;backgroundWorker.WorkerSupportsCancellation = true;backgroundWorker.DoWork += BackgroundWorker_DoWork;backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;}private void startButton_Click(object sender, EventArgs e){if (!backgroundWorker.IsBusy){backgroundWorker.RunWorkerAsync("参数数据");}}private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e){BackgroundWorker worker = sender as BackgroundWorker;string argument = e.Argument as string;for (int i = 1; i <= 100; i++){if (worker.CancellationPending){e.Cancel = true;break;}// 模拟耗时操作Thread.Sleep(50);// 报告进度worker.ReportProgress(i, "处理中..." + argument);}e.Result = "操作完成";}private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e){progressBar.Value = e.ProgressPercentage;statusLabel.Text = e.UserState as string;}private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){if (e.Cancelled){statusLabel.Text = "操作已取消";}else if (e.Error != null){statusLabel.Text = "错误: " + e.Error.Message;}else{statusLabel.Text = e.Result as string;}}
}
三、线程同步和保护机制
3.1 lock语句(Monitor类)
lock是最常用的同步机制,基于Monitor类实现。
using System;
using System.Threading;class LockExample
{private static object lockObject = new object();private static int sharedCounter = 0;static void Main(){Thread[] threads = new Thread[5];for (int i = 0; i < 5; i++){threads[i] = new Thread(IncrementCounter);threads[i].Start();}foreach (var thread in threads){thread.Join();}Console.WriteLine("最终计数: " + sharedCounter);}static void IncrementCounter(){for (int i = 0; i < 1000; i++){// 使用lock保护共享资源lock (lockObject){sharedCounter++;Console.WriteLine("线程 {0}: 计数 = {1}", Thread.CurrentThread.ManagedThreadId, sharedCounter);}}}// 使用Monitor类的等价实现static void IncrementCounterWithMonitor(){for (int i = 0; i < 1000; i++){bool lockTaken = false;try{Monitor.Enter(lockObject, ref lockTaken);sharedCounter++;}finally{if (lockTaken)Monitor.Exit(lockObject);}}}// 带超时的锁static void TryEnterExample(){if (Monitor.TryEnter(lockObject, TimeSpan.FromSeconds(1))){try{// 临界区代码sharedCounter++;}finally{Monitor.Exit(lockObject);}}else{Console.WriteLine("无法获取锁");}}
}
3.2 Mutex(互斥量)
Mutex可用于跨进程同步。
using System;
using System.Threading;class MutexExample
{private static Mutex mutex = new Mutex();private static Mutex namedMutex;static void Main(){// 创建命名互斥量(可跨进程)bool createdNew;namedMutex = new Mutex(false, "Global\\MyApplicationMutex", out createdNew);if (!createdNew){Console.WriteLine("另一个实例正在运行");return;}// 本地互斥量示例Thread[] threads = new Thread[3];for (int i = 0; i < 3; i++){threads[i] = new Thread(MutexProtectedMethod);threads[i].Name = "Thread-" + i;threads[i].Start();}foreach (var thread in threads){thread.Join();}// 清理资源namedMutex.ReleaseMutex();namedMutex.Dispose();mutex.Dispose();}static void MutexProtectedMethod(){Console.WriteLine("{0} 等待获取互斥量", Thread.CurrentThread.Name);mutex.WaitOne();try{Console.WriteLine("{0} 获取到互斥量", Thread.CurrentThread.Name);Thread.Sleep(1000);Console.WriteLine("{0} 完成工作", Thread.CurrentThread.Name);}finally{mutex.ReleaseMutex();Console.WriteLine("{0} 释放互斥量", Thread.CurrentThread.Name);}}
}
3.3 Semaphore(信号量)
Semaphore用于限制同时访问资源的线程数量。
using System;
using System.Threading;class SemaphoreExample
{// 创建信号量,初始计数3,最大计数3private static Semaphore semaphore = new Semaphore(3, 3);static void Main(){// 创建10个线程,但只允许3个同时执行for (int i = 0; i < 10; i++){Thread thread = new Thread(Worker);thread.Name = "Worker-" + i;thread.Start();}Console.ReadKey();semaphore.Dispose();}static void Worker(){Console.WriteLine("{0} 等待进入", Thread.CurrentThread.Name);semaphore.WaitOne();Console.WriteLine("{0} 进入,开始工作", Thread.CurrentThread.Name);Thread.Sleep(2000); // 模拟工作Console.WriteLine("{0} 完成工作", Thread.CurrentThread.Name);semaphore.Release();Console.WriteLine("{0} 离开", Thread.CurrentThread.Name);}
}// 命名信号量(可跨进程)
class NamedSemaphoreExample
{static void Main(){using (Semaphore namedSemaphore = new Semaphore(2, 2, "Global\\MySemaphore")){Console.WriteLine("等待信号量...");namedSemaphore.WaitOne();try{Console.WriteLine("获得信号量,按任意键释放");Console.ReadKey();}finally{namedSemaphore.Release();}}}
}
3.4 ReaderWriterLockSlim(读写锁)
适用于读多写少的场景。
using System;
using System.Threading;
using System.Collections.Generic;class ReaderWriterLockExample
{private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();private static List<int> dataList = new List<int>();private static Random random = new Random();static void Main(){// 创建读线程for (int i = 0; i < 3; i++){Thread readerThread = new Thread(Reader);readerThread.Name = "Reader-" + i;readerThread.Start();}// 创建写线程for (int i = 0; i < 2; i++){Thread writerThread = new Thread(Writer);writerThread.Name = "Writer-" + i;writerThread.Start();}Console.ReadKey();rwLock.Dispose();}static void Reader(){while (true){rwLock.EnterReadLock();try{Console.WriteLine("{0} 读取数据: Count = {1}", Thread.CurrentThread.Name, dataList.Count);if (dataList.Count > 0){Console.WriteLine(" 最后一个元素: " + dataList[dataList.Count - 1]);}}finally{rwLock.ExitReadLock();}Thread.Sleep(1000);}}static void Writer(){while (true){int newValue = random.Next(100);rwLock.EnterWriteLock();try{dataList.Add(newValue);Console.WriteLine("{0} 写入数据: {1}", Thread.CurrentThread.Name, newValue);}finally{rwLock.ExitWriteLock();}Thread.Sleep(2000);}}// 可升级的读锁示例static void UpgradeableReader(){rwLock.EnterUpgradeableReadLock();try{// 读取操作if (dataList.Count > 10){// 需要写入时升级为写锁rwLock.EnterWriteLock();try{dataList.Clear();}finally{rwLock.ExitWriteLock();}}}finally{rwLock.ExitUpgradeableReadLock();}}
}
3.5 AutoResetEvent和ManualResetEvent
用于线程间的信号通知。
using System;
using System.Threading;class EventExample
{// AutoResetEvent:自动重置,一次只允许一个线程通过private static AutoResetEvent autoEvent = new AutoResetEvent(false);// ManualResetEvent:手动重置,允许多个线程同时通过private static ManualResetEvent manualEvent = new ManualResetEvent(false);static void Main(){// AutoResetEvent示例Thread producer = new Thread(Producer);Thread consumer1 = new Thread(Consumer);Thread consumer2 = new Thread(Consumer);consumer1.Name = "Consumer-1";consumer2.Name = "Consumer-2";consumer1.Start();consumer2.Start();producer.Start();Thread.Sleep(5000);// ManualResetEvent示例Console.WriteLine("\n--- ManualResetEvent示例 ---");Thread[] workers = new Thread[3];for (int i = 0; i < 3; i++){workers[i] = new Thread(ManualEventWorker);workers[i].Name = "Worker-" + i;workers[i].Start();}Console.WriteLine("按任意键发送信号...");Console.ReadKey();manualEvent.Set(); // 所有等待的线程都会被释放Thread.Sleep(1000);manualEvent.Reset(); // 重置事件// 清理资源autoEvent.Dispose();manualEvent.Dispose();}static void Producer(){while (true){Thread.Sleep(2000);Console.WriteLine("生产者: 产生数据");autoEvent.Set(); // 通知一个等待的消费者}}static void Consumer(){while (true){autoEvent.WaitOne(); // 等待信号Console.WriteLine("{0}: 消费数据", Thread.CurrentThread.Name);}}static void ManualEventWorker(){Console.WriteLine("{0}: 等待信号", Thread.CurrentThread.Name);manualEvent.WaitOne();Console.WriteLine("{0}: 收到信号,继续执行", Thread.CurrentThread.Name);}
}
3.6 Interlocked类(原子操作)
用于简单的原子操作,无需使用锁。
using System;
using System.Threading;class InterlockedExample
{private static int counter = 0;private static long total = 0;private static object sharedObject = null;static void Main(){Thread[] threads = new Thread[5];for (int i = 0; i < 5; i++){threads[i] = new Thread(InterlockedOperations);threads[i].Start();}foreach (var thread in threads){thread.Join();}Console.WriteLine("最终计数: " + counter);Console.WriteLine("最终总和: " + total);}static void InterlockedOperations(){for (int i = 0; i < 1000; i++){// 原子递增Interlocked.Increment(ref counter);// 原子递减// Interlocked.Decrement(ref counter);// 原子加法Interlocked.Add(ref total, 10);// 原子交换object newObj = new object();object oldObj = Interlocked.Exchange(ref sharedObject, newObj);// 原子比较并交换object comparand = null;Interlocked.CompareExchange(ref sharedObject, newObj, comparand);}}// 使用Interlocked实现线程安全的单例模式class ThreadSafeSingleton{private static ThreadSafeSingleton instance;private static int initialized = 0;public static ThreadSafeSingleton Instance{get{if (instance == null){// 确保只有一个线程创建实例if (Interlocked.CompareExchange(ref initialized, 1, 0) == 0){instance = new ThreadSafeSingleton();}else{// 等待其他线程完成初始化while (instance == null){Thread.Sleep(1);}}}return instance;}}private ThreadSafeSingleton(){Console.WriteLine("单例实例创建");}}
}
3.7 Barrier(屏障)
用于多个线程分阶段协同工作。
using System;
using System.Threading;class BarrierExample
{private static Barrier barrier;static void Main(){int participantCount = 3;// 创建屏障,指定参与者数量和阶段完成时的动作barrier = new Barrier(participantCount, (b) =>{Console.WriteLine("--- 阶段 {0} 完成 ---", b.CurrentPhaseNumber);});// 创建参与线程for (int i = 0; i < participantCount; i++){int threadId = i;Thread thread = new Thread(() => ParticipantWork(threadId));thread.Start();}Console.ReadKey();barrier.Dispose();}static void ParticipantWork(int id){for (int phase = 0; phase < 3; phase++){// 第一阶段工作Console.WriteLine("线程 {0}: 开始阶段 {1} 的工作", id, phase);Thread.Sleep(1000 + id * 500); // 模拟不同的工作时间Console.WriteLine("线程 {0}: 完成阶段 {1} 的工作", id, phase);// 等待其他线程完成当前阶段barrier.SignalAndWait();}Console.WriteLine("线程 {0}: 所有工作完成", id);}
}
3.8 SpinLock(自旋锁)
适用于锁持有时间极短的场景。
using System;
using System.Threading;class SpinLockExample
{private static SpinLock spinLock = new SpinLock();private static int sharedResource = 0;static void Main(){Thread[] threads = new Thread[5];for (int i = 0; i < 5; i++){threads[i] = new Thread(SpinLockWork);threads[i].Start();}foreach (var thread in threads){thread.Join();}Console.WriteLine("最终值: " + sharedResource);}static void SpinLockWork(){for (int i = 0; i < 1000; i++){bool lockTaken = false;try{spinLock.Enter(ref lockTaken);// 临界区:执行时间应该很短sharedResource++;}finally{if (lockTaken){spinLock.Exit();}}}}
}
四、线程安全集合
4.1 ConcurrentDictionary
using System;
using System.Threading;
using System.Collections.Concurrent;class ConcurrentCollectionsExample
{private static ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();private static ConcurrentQueue<int> queue = new ConcurrentQueue<int>();private static ConcurrentBag<int> bag = new ConcurrentBag<int>();private static ConcurrentStack<int> stack = new ConcurrentStack<int>();static void Main(){// ConcurrentDictionary示例Thread[] threads = new Thread[3];for (int i = 0; i < 3; i++){int threadId = i;threads[i] = new Thread(() => DictionaryOperations(threadId));threads[i].Start();}foreach (var thread in threads){thread.Join();}Console.WriteLine("Dictionary包含 {0} 个元素", dictionary.Count);// ConcurrentQueue示例Thread producer = new Thread(QueueProducer);Thread consumer = new Thread(QueueConsumer);producer.Start();consumer.Start();}static void DictionaryOperations(int threadId){for (int i = 0; i < 10; i++){int key = threadId * 10 + i;// 添加或更新dictionary.AddOrUpdate(key, "Value-" + key, // 添加时使用的值(k, oldValue) => "Updated-" + k); // 更新时使用的值// 尝试获取string value;if (dictionary.TryGetValue(key, out value)){Console.WriteLine("线程{0}: 获取 Key={1}, Value={2}", threadId, key, value);}// 获取或添加string newValue = dictionary.GetOrAdd(key + 100, k => "NewValue-" + k);}}static void QueueProducer(){for (int i = 0; i < 20; i++){queue.Enqueue(i);Console.WriteLine("生产: " + i);Thread.Sleep(100);}}static void QueueConsumer(){Thread.Sleep(500); // 让生产者先运行int item;while (true){if (queue.TryDequeue(out item)){Console.WriteLine("消费: " + item);}else{Thread.Sleep(200);}}}
}
五、最佳实践和注意事项
5.1 死锁预防
using System;
using System.Threading;class DeadlockPrevention
{private static object lock1 = new object();private static object lock2 = new object();// 错误示例:可能导致死锁static void WrongMethod1(){lock (lock1){Thread.Sleep(100);lock (lock2){Console.WriteLine("Method1");}}}static void WrongMethod2(){lock (lock2){Thread.Sleep(100);lock (lock1){Console.WriteLine("Method2");}}}// 正确示例:按相同顺序获取锁static void CorrectMethod1(){lock (lock1){lock (lock2){Console.WriteLine("Method1");}}}static void CorrectMethod2(){lock (lock1) // 相同的顺序{lock (lock2){Console.WriteLine("Method2");}}}// 使用超时避免死锁static void TimeoutMethod(){bool lock1Taken = false;bool lock2Taken = false;try{Monitor.TryEnter(lock1, TimeSpan.FromSeconds(1), ref lock1Taken);if (lock1Taken){Monitor.TryEnter(lock2, TimeSpan.FromSeconds(1), ref lock2Taken);if (lock2Taken){// 执行操作Console.WriteLine("获取到所有锁");}else{Console.WriteLine("无法获取lock2");}}}finally{if (lock2Taken)Monitor.Exit(lock2);if (lock1Taken)Monitor.Exit(lock1);}}
}
5.2 线程池最佳实践
class ThreadPoolBestPractices
{static void Main(){// 设置线程池大小int minWorker, minIOC;ThreadPool.GetMinThreads(out minWorker, out minIOC);// 根据CPU核心数设置int processorCount = Environment.ProcessorCount;ThreadPool.SetMinThreads(processorCount, minIOC);ThreadPool.SetMaxThreads(processorCount * 2, minIOC);// 避免在线程池中执行长时间运行的任务// 错误:长时间运行的任务ThreadPool.QueueUserWorkItem(state =>{Thread.Sleep(60000); // 不要这样做});// 正确:长时间任务应使用专门的线程Thread longRunningThread = new Thread(() =>{// 长时间运行的任务while (true){// 处理Thread.Sleep(1000);}});longRunningThread.IsBackground = true;longRunningThread.Start();}
}
5.3 异常处理
class ThreadExceptionHandling
{static void Main(){// 处理未捕获的异常AppDomain.CurrentDomain.UnhandledException += (sender, e) =>{Console.WriteLine("未捕获的异常: " + e.ExceptionObject);};// Thread中的异常处理Thread thread = new Thread(() =>{try{throw new Exception("线程异常");}catch (Exception ex){Console.WriteLine("捕获异常: " + ex.Message);}});thread.Start();// ThreadPool中的异常处理ThreadPool.QueueUserWorkItem(state =>{try{// 工作代码throw new InvalidOperationException("操作异常");}catch (Exception ex){// 记录异常Console.WriteLine("线程池异常: " + ex.Message);}});}
}
六、总结
本指南涵盖了.NET Framework 4.0中多线程编程的主要概念和技术:
- 线程类型:前台线程、后台线程、UI线程
- 线程创建:Thread类、ThreadPool、BackgroundWorker
- 同步机制:lock、Mutex、Semaphore、ReaderWriterLockSlim
- 信号机制:AutoResetEvent、ManualResetEvent、Barrier
- 原子操作:Interlocked类
- 线程安全集合:Concurrent系列集合
- 最佳实践:死锁预防、异常处理、性能优化
选择合适的线程机制取决于具体场景:
- 简单同步使用lock
- 跨进程同步使用Mutex
- 限制并发数使用Semaphore
- 读多写少使用ReaderWriterLockSlim
- 简单原子操作使用Interlocked
- 短期任务使用ThreadPool
- 长期任务使用Thread
- Windows Forms后台操作使用BackgroundWorker
记住始终要正确处理异常、避免死锁、合理使用资源,并在不需要时及时释放同步对象。