【问题标题】:Optional thread safety (thread safe section only under condition)可选的线程安全(线程安全部分仅在条件下)
【发布时间】:2015-12-21 11:38:50
【问题描述】:

如标题所述,我有这种情况

lock ( _myLockObj )
{
    // protected section here ( select + update over SQL Tables)
}

这很好用,但有时我不需要线程安全,因为数据保证不会发生任何错误(即使两个线程并行运行)但我需要速度。 目前程序可以理解线程何时可能存在线程安全问题,何时不存在(什么时候我需要尽可能快)。

我要实现的是该锁定指令的可选性,因此只有在适当的条件为真时它才会生效。

例如:

lock ( _myLockObj ) && flag

我很确定 lock 关键字不提供这种语义,我会理解实现该行为的正确方法是什么。

【问题讨论】:

  • 当你说你不需要线程安全时,你的意思是你知道锁对象不可能被锁定吗?或者你的意思是它可以被锁定但你仍然不需要获取它? (如果是后者,为什么不通过更细粒度的锁来解决呢?)
  • 我的方法是完全线程安全的,所以一般我不需要锁。不是线程安全的是使用 linq 进行的表操作,因为数据库是跨每个线程的共享资源。可能会发生两个线程尝试对同一数据进行两次不同的操作,这是一个问题。这种情况很少见,我可以理解它什么时候可能发生,什么时候肯定不能(大多数数据只需要插入,并且保证是一次插入)。当我确定它不会发生时,我会避免锁定指令(以获得速度)
  • @Skary 使用数据库事务处理它可能会更好,而不是线程同步。
  • @Jakub 我害怕分布式事务(我需要启用它才能以这种方式进行)。不仅如此,过去我使用事务作为解决方案(特别是使用 linq Select + Update)有奇怪的行为。我对过去的问题的原因没有很好的看法,但最后我决定避免交易,我尽可能多地使用这种方法。
  • select + insert 的问题是它在获得共享锁后会尝试获得排他锁。根据事务隔离级别,这将导致在select 之后立即释放共享锁(并允许 T1:Select - T2:Select - T2:Update - T1:Update 序列),或者如果锁被保留则死锁。您需要先获得一个独占锁才能使其正常工作(您应该能够找到一些方法来在 SO 上执行此操作)。线程同步的一个问题是它只能在一个进程(或机器,如果你使用像命名互斥锁之类的东西)内工作

标签: c# multithreading locking


【解决方案1】:

lock 语句是 Monitor.Enter + Monitor.Exittry/finally 块中的语法糖。

您可以直接使用这些方法:

bool flag = false;
bool acquiredLock = false;
try
{
    if (flag)
    {
        Monitor.Enter(_myLockObj, ref acquiredLock);
    }


}
finally
{
    if (flag & acquiredLock)
    {
        Monitor.Exit(_myLockObj);
    }
}

【讨论】:

    【解决方案2】:

    我个人认为以下更好:

    private bool flag;
    
    public T DoStuff() {
      T DoStuffUnsafe() {
        // ...
      }
      if (flag) {
        lock (_myLockObj) {
          return DoStuffUnsafe();
        }
      }
      else {
        return DoStuffUnsafe();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-31
      • 2015-09-29
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      相关资源
      最近更新 更多