【问题标题】:Preventing Threads from Unnecessarily Executing Costly Task防止线程不必要地执行代价高昂的任务
【发布时间】:2016-06-21 12:00:53
【问题描述】:

我想通过以下方式保护对资源的访问:

  • 所有线程都可以并发读取,更新期间除外(如果更新不是原子的)。
  • 只能为一个线程分配更新任务,直到下一次 需要更新。

这似乎是一个简单的问题,使用正确的lock,或者可能使所有操作都原子化,但我认为不是这样。

如果我只有一个用于更新的写锁(即ReaderWriterLockSlim),或者使用非锁定代码,则只有一个线程可以运行更新过程(或排队执行此操作)。如果我在检查资源是否需要更新之前使用锁定来阻塞线程,它们就不能并发执行,但会被有效地序列化。

我可以让特定线程执行资源的所有检查和更新,并利用ManualResetEvent 之类的东西来暂停其他读取线程,直到更新完成。 (或者,如果更新是作为原子操作实现的,则只需满足于具有特定的更新线程。)

但是,我不确定最佳实践,我想问一下您是否认为可以通过更少的努力来满足要求,或者我的任何假设是否都存在偏差。

【问题讨论】:

  • 奇怪的问题。如果您的线程非常不守规矩,以至于您无法在代码中确保您只启动一次执行更新的线程,那么您也无法保证它们表现良好并正确使用 RWLS。添加额外的锁只会让你陷入僵局。这从来都不是一个真正的问题,不要让它成为一个问题。
  • 你为什么要控制访问实例的线程?请随时解释您如何确定“这永远不是真正的问题”。似乎是一个奇怪的评论。

标签: c# multithreading concurrency locking


【解决方案1】:

我认为您正在寻找ReaderWriterLockSlim。写入时使用排他锁模式。

【讨论】:

  • 我知道ReaderWriterLockSlim 类,但我无法提出一种使用模式来防止线程排队执行不必要的更新,即使使用独占锁定模式进行写入也是如此。这就是我试图在我的问题中解释的内容 - “如果我只有一个用于更新的写锁 [...],没有什么能阻止多个线程运行更新过程(或排队执行此操作)”。
  • 我忽略了这一点。尝试以零超时获取写锁,并在锁忙的情况下跳过更新。
  • 我明白你的想法,但该线程仍需要返回值。所以,我需要回去再试一次,可能会进入“更新模式”几次,直到“第一个线程”完成更新资源。对我来说似乎有点不干净。还是我弄错了?
  • 我看到了这个问题。将可写资源设为Lazy<T>。一个写者可以在写锁下创建一个新的惰性并立即退出。然后,任何先出现的线程都会强制懒惰者运行。完成后,所有线程都会获取相同的值。
  • 有趣。我不会想到为此使用Lazy<T> 类。我得试一试。请您用代码 sn-p 更新您的答案,这样如果我接受这是我接受的答案,其他人可能更容易看到原因?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 2020-05-20
  • 1970-01-01
  • 2013-11-23
  • 2021-09-19
  • 1970-01-01
相关资源
最近更新 更多