2026/1/11 14:30:04
网站建设
项目流程
山西省工程招标网,seo链接提交入口,简述seo的基本步骤,网站怎么做图片动态图片不显示一、C# 线程同步的核心概念与作用线程同步是多线程编程中控制共享资源访问顺序的技术#xff0c;目的是解决竞态条件#xff08;多个线程无序操作共享资源导致数据不一致#xff09;#xff0c;确保程序在多线程环境下的数据正确性和行为可预测性。核心作用#xff1a;保证…一、C# 线程同步的核心概念与作用线程同步是多线程编程中控制共享资源访问顺序的技术目的是解决竞态条件多个线程无序操作共享资源导致数据不一致确保程序在多线程环境下的数据正确性和行为可预测性。核心作用保证原子性将多步操作如a a 1变为 “不可分割” 的原子操作避免中间状态被其他线程干扰。保证可见性确保一个线程对共享变量的修改能被其他线程立即感知避免 CPU 缓存导致的 “脏读”。保证有序性禁止编译器 / CPU 对指令的乱序优化确保代码执行顺序符合预期。二、C# 中常用的线程同步方式1. 线程同步的意义基础案例未同步的问题问题场景多个线程同时修改共享计数器导致结果错误。using System; using System.Threading; class ThreadSyncDemo { // 共享资源未同步的计数器 private static int _counter 0; static void Main() { Console.WriteLine( 未同步的计数器 ); // 启动10个线程同时递增计数器 for (int i 0; i 10; i) { new Thread(IncrementCounter).Start(); } // 等待所有线程完成简单模拟实际应使用Join Thread.Sleep(1000); Console.WriteLine($最终计数器值{_counter}); // 预期10实际可能小于10 } static void IncrementCounter() { // 非原子操作读取→递增→写入 int temp _counter; Thread.Sleep(1); // 模拟耗时操作放大竞态条件 _counter temp 1; Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}当前值{_counter}); } }输出示例 未同步的计数器 线程4当前值1 线程5当前值1 线程6当前值2 线程7当前值3 ... 最终计数器值8原因多个线程同时读取_counter的旧值导致递增操作被覆盖。2. 监视器Monitor与 lock 关键字lock是Monitor的语法糖保证临界区代码互斥执行。using System; using System.Threading; class MonitorLockDemo { private static int _counter 0; // 锁对象必须是引用类型且私有只读避免外部干扰 private static readonly object _lockObj new object(); static void Main() { Console.WriteLine( 使用lock的计数器 ); for (int i 0; i 10; i) { new Thread(IncrementCounterWithLock).Start(); } Thread.Sleep(1000); Console.WriteLine($最终计数器值{_counter}); // 稳定输出10 } static void IncrementCounterWithLock() { // lock自动包含try-finally确保锁释放 lock (_lockObj) { int temp _counter; Thread.Sleep(1); _counter temp 1; Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}当前值{_counter}); } } }输出 使用lock的计数器 线程4当前值1 线程5当前值2 线程6当前值3 ... 最终计数器值10原理lock会调用Monitor.Enter(_lockObj)获取锁finally中调用Monitor.Exit(_lockObj)释放锁确保同一时间只有一个线程进入临界区。3. LockC# 13 新特性C# 13 引入的System.Threading.Lock通过作用域自动管理锁比Monitor更简洁高效。using System; using System.Threading; using System.Threading.Tasks; class NewLockDemo { private static int _counter 0; // C# 13的Lock类型 private static readonly Lock _newLock new Lock(); static async Task Main() { Console.WriteLine( 使用C# 13 Lock的计数器 ); // 启动10个并发任务 Task[] tasks new Task[10]; for (int i 0; i 10; i) { tasks[i] Task.Run(IncrementCounterWithNewLock); } await Task.WhenAll(tasks); Console.WriteLine($最终计数器值{_counter}); // 稳定输出10 } static void IncrementCounterWithNewLock() { // using作用域结束时自动释放锁 using (_newLock.EnterScope()) { int temp _counter; Thread.Sleep(1); _counter temp 1; Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}当前值{_counter}); } } }优势无需手动处理try-finally锁生命周期与代码块一致降低死锁风险。4. volatile 关键字volatile确保变量的可见性禁止 CPU 缓存和有序性禁止指令重排但不保证原子性。using System; using System.Threading; class VolatileDemo { // volatile标记确保线程间可见 private static volatile bool _isRunning true; static void Main() { Console.WriteLine( volatile示例 ); new Thread(Worker).Start(); // 主线程修改_isRunning Thread.Sleep(1000); _isRunning false; Console.WriteLine(主线程已设置_isRunningfalse); } static void Worker() { int count 0; // 若_isRunning不标记volatileWorker可能永远无法感知到修改 while (_isRunning) { count; } Console.WriteLine($Worker线程退出循环执行次数{count}); } }输出 volatile示例 主线程已设置_isRunningfalse Worker线程退出循环执行次数...注意volatile仅适用于bool、int等简单类型复杂操作如_counter仍需配合锁。5. System.Threading.Interlocked提供原子操作如递增、交换底层由 CPU 指令支持比锁更高效。using System; using System.Threading; class InterlockedDemo { private static int _counter 0; static void Main() { Console.WriteLine( Interlocked原子操作 ); for (int i 0; i 10; i) { new Thread(IncrementWithInterlocked).Start(); } Thread.Sleep(1000); Console.WriteLine($最终计数器值{_counter}); // 稳定输出10 } static void IncrementWithInterlocked() { // 原子递增读取→递增→写入是一个不可分割的操作 Interlocked.Increment(ref _counter); Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}当前值{_counter}); Thread.Sleep(1); } }常用方法Increment(ref int)原子递增Decrement(ref int)原子递减Exchange(ref T, T)原子交换值CompareExchange(ref T, T, T)原子比较并交换6. System.Threading.MutexMutex互斥锁支持跨进程同步比lock更重涉及系统调用。using System; using System.Threading; class MutexDemo { private static int _counter 0; // 命名Mutex支持跨进程同步 private static readonly Mutex _mutex new Mutex(false, MyAppMutex); static void Main() { Console.WriteLine( Mutex示例 ); for (int i 0; i 10; i) { new Thread(IncrementWithMutex).Start(); } Thread.Sleep(1000); Console.WriteLine($最终计数器值{_counter}); // 稳定输出10 } static void IncrementWithMutex() { // 请求获取Mutex阻塞直到获取 _mutex.WaitOne(); try { int temp _counter; Thread.Sleep(1); _counter temp 1; Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}当前值{_counter}); } finally { // 必须释放Mutex否则其他线程永久阻塞 _mutex.ReleaseMutex(); } } }场景确保应用程序单实例运行、跨进程共享文件 / 硬件资源。7. 重新发送事件线程同步中的 “重试机制”当线程获取锁失败时通过重试 延迟避免频繁竞争提升性能。using System; using System.Threading; class RetryEventDemo { private static int _counter 0; private static readonly object _lockObj new object(); static void Main() { Console.WriteLine( 重新发送事件重试机制 ); for (int i 0; i 10; i) { new Thread(IncrementWithRetry).Start(); } Thread.Sleep(2000); Console.WriteLine($最终计数器值{_counter}); } static void IncrementWithRetry() { bool lockAcquired false; // 重试最多5次每次失败后延迟10ms for (int retry 0; retry 5 !lockAcquired; retry) { // 尝试获取锁超时10ms lockAcquired Monitor.TryEnter(_lockObj, 10); if (lockAcquired) { try { int temp _counter; Thread.Sleep(1); _counter temp 1; Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}当前值{_counter}第{retry1}次尝试成功); } finally { Monitor.Exit(_lockObj); } } else { Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}第{retry1}次尝试获取锁失败重试...); } } } }输出示例 重新发送事件重试机制 线程4第1次尝试获取锁失败重试... 线程5第1次尝试获取锁成功当前值1 线程4第2次尝试获取锁成功当前值2 ...8. 线程本地存储TLS为每个线程创建独立的变量副本避免共享资源竞争无需同步。C# 中常用ThreadLocalT实现。using System; using System.Threading; class ThreadLocalStorageDemo { // 每个线程有独立的计数器副本 private static ThreadLocalint _threadLocalCounter new ThreadLocalint(() 0); static void Main() { Console.WriteLine( 线程本地存储 ); // 启动3个线程每个线程递增自己的副本 for (int i 0; i 3; i) { new Thread(IncrementThreadLocalCounter).Start(); } Thread.Sleep(1000); Console.WriteLine(主线程所有线程执行完毕); } static void IncrementThreadLocalCounter() { for (int i 0; i 3; i) { _threadLocalCounter.Value; Console.WriteLine($线程{Thread.CurrentThread.ManagedThreadId}本地计数器{_threadLocalCounter.Value}); Thread.Sleep(100); } // 释放资源可选 _threadLocalCounter.Dispose(); } }输出 线程本地存储 线程4本地计数器1 线程5本地计数器1 线程6本地计数器1 线程4本地计数器2 线程5本地计数器2 ...优势完全避免线程间竞争适用于 “每个线程独立状态” 的场景如数据库连接缓存。三、总结C# 线程同步的核心是控制共享资源的访问顺序不同技术的适用场景技术核心作用适用场景lock/Monitor互斥访问临界区大多数共享资源同步System.Threading.Lock简化锁管理C# 13 的高性能同步volatile保证可见性 / 有序性简单变量的线程间状态同步Interlocked原子操作简单数值的递增 / 交换Mutex跨进程同步多进程共享资源重新发送事件减少锁竞争高并发场景的锁重试ThreadLocalT线程独立副本每个线程的私有状态补充说明选型核心原则优先选轻量级方案能不用锁就不用如 ThreadLocal→ 能用原子操作就不用锁Interlocked→ 能用用户态锁lock/Lock就不用内核态锁Mutex避免过度同步仅对 “真正共享的资源” 加同步线程私有数据直接用 TLS死锁规避lock/Mutex 需保证 “锁的获取顺序一致”如先锁 A 再锁 B所有线程都遵循尽量缩短临界区代码只包裹必要操作避免在锁内做 IO / 耗时计算性能权衡高并发计数器优先 Interlocked而非 lock跨进程同步只能用 Mutex简单状态标记用 volatile 替代 lock。