使用ReaderWriterLockSlim锁定函数参数以解决索引越界问题
问题描述
Class1基于后端JSON流创建动态静态对象dynamObj,更新dynamObj时使用锁。Class2获取该dynamObj做进一步处理,但遍历其数组类型属性时偶尔触发索引越界异常。现提出以下问题:
- 在Class2中,当
Method2(dynamObjCopy)执行期间,若原始静态dynamObj被更新,dynamObjCopy参数会自动更新吗?换句话说,while循环执行时PropertyArray的Length是否会变化? - 若这是索引越界的原因,如何锁定
Method2的参数dynamObjCopy以阻止其更新?像Class1那样锁定Method2整个函数体是否可行?
简化示例代码
public class Class1 { public static dynamic dynamObj = null; public static ReaderWriterLockSlim locker = new ReaderWriterLockSlim(); try { locker.EnterWriteLock(); dynamObj = deserializedDynamObjFromJSONstream; } finally { locker.ExitWriteLock(); } } public class Class2 { public dynamic Method1() { dynamic dynamObjCopy = dynamObj; Method2(dynamObjCopy); } private dynamic Method2(dynamic dynamObjCopy) { var ind = 0; while (ind < dynamObjCopy.PropertyArray.Length) {// 此处偶尔触发索引越界异常 someList.Add(dynamObjCopy.PropertyArray[ind]); ind++; } } }
问题解答
问题1解答
分两种情况:
- 如果Class1更新
dynamObj是直接替换整个对象引用(如示例代码中dynamObj = deserializedDynamObjFromJSONstream),那dynamObjCopy会保留旧对象的引用,其PropertyArray的Length不会随新dynamObj变化,理论上不会触发索引越界。 - 如果更新操作是修改原有
dynamObj内部的PropertyArray实例(比如直接缩短数组、替换数组引用),那dynamObjCopy因为指向同一个对象实例,遍历过程中PropertyArray的Length可能突然变小,导致索引越界。
问题2解答
锁定dynamObjCopy本身没用,它只是个引用。核心是要保证读取dynamObj及其内部属性的全程,不会有写入操作修改目标对象:
- 复用Class1的
ReaderWriterLockSlim锁,在读取+遍历的全流程加读锁:
必须在获取对象引用到完成遍历的整个阶段持有读锁,确保Class1的写锁无法抢占,避免对象被修改。示例代码调整如下:public dynamic Method1() { Class1.locker.EnterReadLock(); try { var someList = new List<object>(); var ind = 0; while (ind < Class1.dynamObj.PropertyArray.Length) { someList.Add(Class1.dynamObj.PropertyArray[ind]); ind++; } return someList; } finally { Class1.locker.ExitReadLock(); } } - 若一定要用副本,需在锁内创建深拷贝:浅拷贝只会复制对象引用,内部的
PropertyArray仍指向同一个实例,依然可能被修改。 - 单独锁定Method2整个函数体不可行:如果用新锁,无法和Class1的写锁同步;如果用Class1的锁,
dynamObjCopy可能在Method1获取时就已处于“待修改”状态,锁无法覆盖从获取引用到进入Method2的这段空白期。
内容的提问来源于stack exchange,提问作者user2217057
相关产品推荐
相关产品推荐

