对多种方法使用同一个锁

发布于 2024-10-09 03:43:39 字数 1042 浏览 0 评论 0原文

到目前为止,我还没有对多个方法使用相同的锁遇到任何问题,但我想知道以下代码是否实际上可能存在我不知道的问题(性能?):

private static readonly object lockObj = new object();

public int GetValue1(int index)
{
    lock(lockObj)
    {
        // Collection 1 read and/or write
    }
}

public int GetValue2(int index)
{
    lock(lockObj)
    {
        // Collection 2 read and/or write
    }
}

public int GetValue3(int index)
{
    lock(lockObj)
    {
        // Collection 3 read and/or write
    }
}

这 3 个方法和集合不是无论如何都相关。

另外,如果这个lockObj也被单例使用(在Instance属性中),会不会有问题?

编辑:澄清我关于在 Singleton 类中使用相同锁定对象的问题:

private static readonly object SyncObject = new object();

public static MySingleton Instance
{
    get
    {
        lock (SyncObject)
        {
          if (_instance == null)
          {
              _instance = new MySingleton();
          }
        }
        return _instance;
    }
}

public int MyMethod()
{
      lock (SyncObject)
      {
           // Read or write
      }  
}

这会导致问题吗?

I haven't had any issues using the same lock for multiple methods so far, but I'm wondering if the following code might actually have issues (performance?) that I'm not aware of:

private static readonly object lockObj = new object();

public int GetValue1(int index)
{
    lock(lockObj)
    {
        // Collection 1 read and/or write
    }
}

public int GetValue2(int index)
{
    lock(lockObj)
    {
        // Collection 2 read and/or write
    }
}

public int GetValue3(int index)
{
    lock(lockObj)
    {
        // Collection 3 read and/or write
    }
}

The 3 methods and the collections are not related in anyway.

In addition, will it be a problem if this lockObj is also used by a singleton (in Instance property) ?

Edit: To clarify my question on using the same lock object in a Singleton class:

private static readonly object SyncObject = new object();

public static MySingleton Instance
{
    get
    {
        lock (SyncObject)
        {
          if (_instance == null)
          {
              _instance = new MySingleton();
          }
        }
        return _instance;
    }
}

public int MyMethod()
{
      lock (SyncObject)
      {
           // Read or write
      }  
}

Will this cause issues?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

千纸鹤带着心事 2024-10-16 03:43:39

如果这些方法如您所述不相关,则为每个方法使用不同的锁;否则效率很低(因为不同的方法没有理由锁定同一个对象,因为它们可以安全地并发执行)。

另外,这些似乎是锁定静态对象的实例方法——这是有意的吗?我有一种感觉,这是一个错误;实例方法(通常)应该只锁定实例字段。

关于单例设计模式:

虽然锁定对于这些人来说是安全的,但更好的做法是对字段进行延迟初始化,如下所示:

private static object sharedInstance;
public static object SharedInstance
{
     get
     {
          if (sharedInstance == null)
              Interlocked.CompareExchange(ref sharedInstance, new object(), null);
          return sharedInstance;
     }
}

这种方式会更快一些(因为互锁方法更快,而且因为初始化被延迟),但仍然是线程安全的。

If the methods are unrelated as you state, then use a different lock for each one; otherwise it's inefficient (since there's no reason for different methods to lock on the same object, as they could safely execute concurrently).

Also, it seems that these are instance methods locking on a static object -- was that intended? I have a feeling that's a bug; instance methods should (usually) only lock on instance fields.

Regarding the Singleton design pattern:

While locking can be safe for those, better practice is doing a delayed initialization of a field like this:

private static object sharedInstance;
public static object SharedInstance
{
     get
     {
          if (sharedInstance == null)
              Interlocked.CompareExchange(ref sharedInstance, new object(), null);
          return sharedInstance;
     }
}

This way it's a little bit faster (both because interlocked methods are faster, and because the initialization is delayed), but still thread-safe.

小糖芽 2024-10-16 03:43:39

通过在所有这些方法中使用同一个对象锁定,您可以序列化对所有线程中代码的所有访问

也就是说...运行 GetValue1() 的代码将阻止不同线程中的其他代码运行 GetValue2(),直到完成为止。如果您添加更多锁定同一对象实例的代码,那么您最终将在某个时刻得到有效的单线程应用程序。

By using the same object to lock on in all of those methods, you are serializing all access to code in all of the threads.

That is... code running GetValue1() will block other code in a different thread from running GetValue2() until it's done. If you add even more code that locks on the same object instance, you'll end up with effectively a single-threaded application at some point.

你不是我要的菜∠ 2024-10-16 03:43:39

共享锁会锁定其他不相关的调用

如果您使用相同的锁,那么锁定一种方法也会不必要地锁定其他方法。如果他们根本没有关系,那么这就是一个问题,因为他们必须互相等待。他们不应该这样做。

瓶颈

当这些方法被频繁调用时,这可能会造成瓶颈。使用单独的锁,它们将独立运行,但共享相同的锁意味着它们必须根据需要更频繁地等待锁被释放(实际上频率是三倍)。

Shared lock locks other non-related calls

If you use the same lock then locking in one method unnecessarily locks others as well. If they're not related at all than this is a problem since they have to wait for each other. Which they shouldn't.

Bottleneck

This may pose a bottleneck when these methods are frequently called. With separate locks they would run independently, but sharing the same lock it means they must wait for the lock to be released more often as required (actually three times more often).

请叫√我孤独 2024-10-16 03:43:39

要创建线程安全的单例,请使用此技术
你不需要锁。

一般来说,每个锁应该尽量少用。
锁定同一事物的方法越多,当您真正不需要时,您就越有可能最终等待它。

To create a thread-safe singleton, use this technique.
You don't need a lock.

In general, each lock should be used as little as possible.
The more methods lock on the same thing, the mroe likely you are to end up waiting for it when you don't really need to.

初懵 2024-10-16 03:43:39

好问题。使锁更细粒度与更粗粒度各有利弊,一个极端是为每条数据单独加锁,另一个极端是为整个程序加一个锁。正如其他帖子指出的那样,重用相同锁的缺点通常是您可能会获得更少的并发性(尽管这取决于情况,但您可能不会获得更少的并发性)。

然而,使用更多锁的缺点通常是更有可能发生死锁。涉及的锁越多,导致死锁的方法就越多。例如,在单独的线程中同时获取两个锁但顺序相反是一种潜在的死锁,如果只涉及一个锁则不会发生这种死锁。当然,有时您可以通过将一个锁分成两个来解决死锁,但通常锁越少意味着死锁越少。拥有更多锁还增加了代码复杂性。

一般来说,这两个因素需要平衡。为了方便起见,如果不会导致任何并发问题,通常每个类使用一个锁。事实上,这样做是一种称为监视器的设计模式。

我想说,最佳实践是为了代码简单性而倾向于使用更少的锁,如果有充分的理由(例如并发性,或者更简单或修复死锁的情况),则创建额外的锁。

Good question. There are pros and cons of making locks more fine grained vs more coarse grained, with one extreme being a separate lock for each piece of data and the other extreme being one lock for the entire program. As other posts point out, the disadvantage of reusing the same locks is in general you may get less concurrency (though it depends on the case, you may not get less concurrency).

However, the disadvantage of using more locks is in general you make deadlock more likely. There are more ways to get deadlocks the more locks you have involved. For example, acquiring two locks at the same time in separate threads but in the opposite order is a potential deadlock which wouldn't happen if only one lock were involved. Of course sometimes you may fix a deadlock by breaking one lock into two, but usually fewer locks means fewer deadlocks. There's also added code complexity of having more locks.

In general these two factors need to be balanced. It's common to use one lock per class for convenience if it doesn't cause any concurrency issues. In fact, doing so is a design pattern called a monitor.

I would say the best practice is to favor fewer locks for code simplicity's sake and make additional locks if there's a good reason (such as concurrency, or a case where it's more simple or fixes a deadlock).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文