Skip to content

Commit ac1e083

Browse files
committed
fix(options): 修复 OptionsProvider 线程安全和可见性问题
- 添加 volatile 关键字到 _args 字段,确保多线程可见性 (C-001) - 实现双重检查锁定模式优化并发性能 (H-004) - 在锁外构建选项对象,避免长时间持有锁
1 parent 9f16252 commit ac1e083

1 file changed

Lines changed: 11 additions & 5 deletions

File tree

GameFrameX.Foundation.Options/OptionsProvider.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static class OptionsProvider
4040
{
4141
private static readonly System.Collections.Concurrent.ConcurrentDictionary<Type, object> OptionsCache = new();
4242
private static readonly object _lock = new();
43-
private static string[] _args;
43+
private static volatile string[] _args;
4444

4545
/// <summary>
4646
/// 初始化选项提供者
@@ -124,7 +124,7 @@ private static bool ShouldEnableDebugOutput(bool? enableDebugOutput = null)
124124
var type = typeof(T);
125125
var shouldDebug = ShouldEnableDebugOutput(enableDebugOutput);
126126

127-
// 如果缓存中已存在,直接返回
127+
// 第一次检查缓存(无锁快速路径)
128128
if (OptionsCache.TryGetValue(type, out var cachedOptions))
129129
{
130130
var cachedResult = (T)cachedOptions;
@@ -139,16 +139,22 @@ private static bool ShouldEnableDebugOutput(bool? enableDebugOutput = null)
139139
return cachedResult;
140140
}
141141

142-
// 创建选项构建器
142+
// 缓存未命中,进入锁保护区域
143143
string[] args;
144144
lock (_lock)
145145
{
146+
// 双重检查:再次检查缓存(可能在等待锁时被其他线程填充)
147+
if (OptionsCache.TryGetValue(type, out cachedOptions))
148+
{
149+
return (T)cachedOptions;
150+
}
151+
152+
// 获取参数(在同一个锁内,确保与 Initialize 同步)
146153
args = _args ?? Array.Empty<string>();
147154
}
148155

156+
// 在锁外构建选项(避免长时间持有锁)
149157
var builder = new OptionsBuilder<T>(args);
150-
151-
// 构建选项
152158
var options = builder.Build(skipValidation);
153159

154160
// 缓存选项(使用 GetOrAdd 确保线程安全)

0 commit comments

Comments
 (0)