需要改进的线程锁定建议

Dom*_*ius 5 c# multithreading locking

我有以下场景:

我正在尝试锁定一个线程,如果该线程的'custom'id与已经进入已锁定部分的代码匹配,但是如果id不同则不匹配.

我创建了一些示例代码来解释我想要的行为

class A
{        
    private static Dictionary<int, object> _idLocks = new Dictionary<int, object>();
    private static readonly object _DictionaryLock = new object();
    private int _id;

    private void A (int id)
    {
        _id = id;
    }

    private object getObject()
    {
        lock (_DictionaryLock)
        {
            if (!_idLocks.ContainsKey(_id))
                _idLocks.Add(_id, new object());
        }
        lock (_idLocks[_id])
        {
            if (TestObject.Exists(_id))
                return TestObject(_id);
            else
                return CreateTestObject(_id);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这对于我扩展的内容100%工作,其中id示例1不检查是否已创建其对象,而另一个id为1的线程已经忙于创建该对象.

但是拥有两个锁和一个静态字典似乎并不是正确的做法,所以我希望有人能告诉我一个改进的方法来阻止线程访问代码只有当该线程创建时具有与一个人已经忙着执行锁定部分的代码.

我正在查看ReaderWriterLockSlim类,但对我来说,使用它并没有多大意义因为我不希望在它仍然被创建的同时读取对象TestObject(id).

我不关心锁定线程访问字典.我试图不惜一切代价避免的是该线程运行的_id不应该在内部使用,CreateTestObject(_id)而已经有一个忙,因为文件正在创建并删除该id,如果两个线程试图访问将抛出异常相同的文件

只需一个普通的锁即可修复,但在这种情况下,我仍然需要一个当前没有在该CreateTestObject(_id)方法内运行的线程能够输入锁内的代码.

这就是因为CreateTestObject内部发生的事情需要时间,如果线程正在等待访问它,性能将受到影响.

Zim*_*oot 3

看起来您正在使用此代码以线程安全的方式填充字典 - 您可以改用ConcurrentDictionary吗?

class A {
  private static ConcurrentDictionary<int, object> _dictionary = new ConcurrentDictionary<int, object>();

  private int _id;

  private object GetObject() {
    object output = null;
    if(_dictionary.TryGetValue(_id, output)) {
      return output;
    } else {
      return _dictionary.GetOrAdd(_id, CreateTestObject(_id));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果您想完全消除调用重复方法的可能性,CreateTestObject那么您可以在_dictionary该延迟集中存储包装器object

class Wrapper {
  private volatile object _obj = null;

  public object GetObj() {
    while(_obj == null) {
      // spin, or sleep, or whatever
    }
    return _obj;
  }

  public void SetObj(object obj) {
    _obj = obj;
  } 
}

class A {
  private static ConcurrentDictionary<int, Wrapper> _dictionary = new ConcurrentDictionary<int, Wrapper>();

  private int _id;

  private object GetObject() {
    Wrapper wrapper = null;
    if(_dictionary.TryGetValue(_id, wrapper)) {
      return wrapper.GetObj();
    } else {
      Wrapper newWrapper = new Wrapper();
      wrapper = _dictionary.GetOrAdd(_id, newWrapper);
      if(wrapper == newWrapper) {
        wrapper.SetObj(CreateTestObject(_id));
      }
      return wrapper.GetObj();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

只有一个线程能够在指定位置放入一个新Wrapper值- 该线程将初始化条件内部的对象。 旋转直到对象被设置,这可以重写为阻塞。_dictionary_idwrapper == newWrapperWrapper#GetObj