如何通过引用在线程间共享值类型变量?
问题分析与可行方案
你写的代码为啥不行
这段代码编译通不过,就算强行绕过编译也会出问题——C#不允许在异步回调(比如ThreadPool的任务)里捕获ref参数。ref绑定的是当前方法的栈帧,Start方法执行完栈就销毁了,后续线程再访问这个引用,轻则拿到错误值,重则直接触发内存访问错误。
不用unsafe的解决办法
值类型本身是栈上分配的,没法跨线程保持引用,我们可以用引用类型当包装器,把值类型包裹进去,这样传递的是包装器的实例引用,跨线程修改内部值就安全了。
办法1:自定义值包装类
写个简单的泛型包装类,把布尔值装进去:
// 泛型包装类,用来包裹值类型 public class ValueBox<T> where T : struct { public T Value { get; set; } } public class User { private ValueBox<bool> _userFlag = new ValueBox<bool>(); public void UserInitHandler() { var handler = new Handler(1000); handler.Start(_userFlag); } // 任意时间检查标记 public bool IsFlagSet() { return _userFlag.Value; } } public class Handler { private readonly int _delay; public Handler(int delay) { _delay = delay; } public void Start(ValueBox<bool> flagBox) { ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(_delay); // 修改包装类内部的值 flagBox.Value = true; }); } }
办法2:用现成的原子布尔类(.NET Core 3.0+可用)
如果你的项目基于.NET Core 3.0及以上版本,直接用System.Threading.AtomicBoolean,它是专门为跨线程布尔值场景设计的,自带线程安全特性:
using System.Threading; public class User { private readonly AtomicBoolean _userFlag = new AtomicBoolean(false); public void UserInitHandler() { var handler = new Handler(1000); handler.Start(_userFlag); } public bool IsFlagSet() { return _userFlag.Value; } } public class Handler { private readonly int _delay; public Handler(int delay) { _delay = delay; } public void Start(AtomicBoolean flag) { ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(_delay); flag.Value = true; }); } }
线程安全小提醒
- 如果标记只会被设置一次,没有多线程同时修改的场景,直接用自定义包装类就足够;
- 如果存在多线程同时读写的情况,建议使用
Interlocked类或者AtomicBoolean,避免出现CPU缓存导致的线程无法读取最新值的问题。
内容的提问来源于stack exchange,提问作者Boppity Bop
相关产品推荐
相关产品推荐

