首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用SyncLock (一般情况下)

正确使用SyncLock (一般情况下)
EN

Stack Overflow用户
提问于 2011-01-26 13:23:11
回答 2查看 28.6K关注 0票数 8

这是一个关于锁定两个列表(共T个)对象的previous question的后续。那里的答案很有帮助,但给我留下了另一个问题。

假设我有一个这样的函数:

代码语言:javascript
复制
Public Function ListWork() As Integer
  List1.Clear()
  ..Some other work which does not modify List1..
  List1.AddRange(SomeArray)
  ..Some more work that does not involve List1..
  Return List1.Count
End Function

它驻留在声明List1的类中。在多线程环境中,我现在明白了,无论何时修改或枚举List1,我都应该有一个私有的锁对象用于List1和锁List1。我的问题是,我是否应该这样做:

代码语言:javascript
复制
Private List1Lock As New Object
Public Function ListWork() As Integer
  SyncLock List1Lock
    List1.Clear()
  End SyncLock
  ..Some other work which does not modify List1..
  SyncLock List1Lock
    List1.AddRange(SomeArray)
  End SyncLock
  ..Some more work that does not involve List1..
  SyncLock List1Lock
    Dim list1Count As Integer = List1.Count
  End SyncLock
  Return list1Count
End Function

或者这样:

代码语言:javascript
复制
Private List1Lock As New Object
Public Function ListWork() As Integer
  SyncLock List1Lock
    List1.Clear()
    ..Some other work which does not modify List1..
    List1.AddRange(SomeArray)
    ..Some more work that does not involve List1..
    Dim list1Count As Integer = List1.Count
  End SyncLock
  Return list1Count
End Function

我猜前面的例子是最优的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-01-26 14:43:44

从示例中,很难判断哪一个是正确的,如果其中一个是正确的。不过,一些指导原则/观察可能会帮助你回答你的问题,或者知道如何提供额外的信息:

首先,你需要同步吗?让每个线程拥有这个类的一个实例会更有意义吗?如果每个实例都是线程的本地实例,并且只在该线程上修改和使用,则不需要锁定。

如果此类和利用线程的目的是并行处理较大的数据集,则主线程以某种逻辑方式划分任务,然后等待辅助线程完成可能更有意义。在这种情况下,请查看ThreadPool和等待句柄,而不是自己管理线程。那么,大多数肮脏的工作都是为你完成的。

关于同步/锁定:如果您的操作在两个步骤之间中断,数据是否一致/有效?

在你的例子中,假设你有两个线程。第一个线程位于.AddRange().Count之间,当第二个线程进入函数并获取列表上的锁时。

线程1再运行一段时间,就会遇到保护.Count方法的锁,然后进入睡眠状态。在此期间,线程2清除列表,然后释放其锁,唤醒线程1,然后线程1获取该锁。

在这种情况下,当线程1完成构建列表的工作时,线程1将从该函数返回0。然后,列表长度将不会真正为0,因为线程2已经出现并填充了列表。

在这种情况下,各个列表操作周围的锁会破坏程序,因此在ClearCount调用之间使用一个锁更有意义。

简而言之,多线程是引入一整类与Race Conditions相关的细微bug的好方法,这些bug通常会导致Heisenbugs

尽可能避免使用线程通常是明智的做法。如果不能,请尝试以需要最小同步的方式安排工作负载(例如,在开始时为线程提供一组数据,然后等待它发出完成信号,例如链接线程池示例)。如果你不能做到这一点,那么请谨慎行事,并始终问自己“如果两个线程在这个区域运行会发生什么”。

希望这能帮助您为未来的多线程代码冒险做好准备。

票数 11
EN

Stack Overflow用户

发布于 2011-01-26 14:30:48

“视情况而定”。这两个示例具有不同的语义。

在后一个示例中,整个操作集相对于锁是原子的。虽然在前面的示例中,对列表的访问是在锁中保护的,但是不能(正确地)将整个操作集视为原子操作(相对于锁)。

想象一下,如果不同的线程在同一对象上调用ListWork,在操作/线程交错的情况下会发生什么。

祝你编码愉快。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4801618

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档