【问题标题】:Multithreading and Locking (Thread-Safe operations)多线程和锁定(线程安全操作)
【发布时间】:2015-07-04 15:01:55
【问题描述】:

所以我有一个类,其中有几个方法都使用锁定,以防止当有人使用我的类的实例并通过多个线程访问它时发生奇怪的事情:

public class SomeRandomClass
{
    private object locker = new object();

    public void MethodA()
    {
        lock (locker)
        {
            // Does something
            MethodB();
        }
    }

    public void MethodB()
    {
        lock (locker)
        {
            // Does something else
        }
    }
}

正如我们所见,MethodB() 会被 MethodA() 自动访问,但这不起作用,因为 MethodA() 当前已锁定了 locker 对象。

我想让MethodB() 可以公开访问,因此您可以在需要时手动调用它,但我不希望在MethodA() 做事时使用它(这就是我使用储物柜对象的原因)。

当然我不希望MethodA()MethodB() 做事的时候做事。我基本上只希望同时使用所有方法中的一种,但MethodA() 需要以某种方式访问​​MethodB() 而无需移除锁(以便它始终保持完全线程安全)。

我真的希望我想问的问题是可以理解的……如果对我的问题有任何疑问,请继续在下面发布。答案/解决方案也非常感谢!

解决方案可能非常简单,我只是没看到。

顺便说一句,上面应该是C#代码。

【问题讨论】:

  • 我删除了java标签。
  • 所以:欢迎来到 StackOverflow!我认为您的问题写得非常清楚和出色。我们不喜欢“谢谢”短语(它们只会分散注意力),所以我从你的问题中删除了这个短语。
  • @DrewPierce:对不起,我真的不明白你的问题。你介意在你可能是英文的评论中使用完整的单词吗?
  • 我将在 Android 上使用我的麦克风,以便 Marcus 能够理解
  • 您的代码应该按原样工作。看到这个帖子:stackoverflow.com/a/13017319/3495581

标签: c# multithreading thread-safety locking


【解决方案1】:

一个简单的解决方案是创建一个 private 方法,其中包含 MethodB 所做的事情,可以由 MethodA 和另一个 public MethodB 调用 p>

privateMethodB 不会锁定,只有公共的会锁定。

例如:

public class SomeRandomClass {

    private object locker = new object();

    public void MethodA {
        lock(locker) {
            // exclusive club
            // do something before calling _methodB
            _methodB();
        }
    }
    private void _methodB {
        // do that, what used to be done by MethodB
    }
    public void MethodB {
        //this one only exists to expose _methodB in a thread-safe context
        lock(locker) {      
            _methodB();
        }
    }
}

附言

我认为你和其他人都明白为什么你的代码在某种程度上设计会造成死锁。


更新

显然lock(object) {}re-entrant,正如 cmets 中所指出的,所以明显的死锁甚至不是一个。

【讨论】:

    【解决方案2】:

    锁定禁止您尝试做的事情——这就是它的目的。

    这里要做的一件事是创建一个私有方法,您可以从methodAmethodB 访问它。该方法不使用锁定,也不是线程安全的,但可以从任一锁定方法调用。

    【讨论】:

    • 是的,我一直在考虑创建一个可以被他们俩访问的私有方法,只是不确定从程序员的角度来看是否可以,因为我可能必须创建然后有很多私有方法,因为我有很多公共方法都在我的应用程序中使用锁定(在编程方面我仍然有点缺乏经验)。谢谢你的帮助! (我希望可以在 cmets 中说“谢谢”)。
    • 好吧,只是不要发送垃圾邮件:) 尤其是在讨论您的问题或答案时,这绝对没问题。
    【解决方案3】:

    你在这里有竞争条件:它使数据不正确。我想方法A写静态theVar字符串类型变量:

    thread A -> call method A -> lock -> change theVar to "A"
    thread B -> call method B -> wait because thread A keep lock
    thread A -> release lock to call method B
        The bug here: thread B process theVar of "A"
        If method B only read theVar, it's Ok.
    

    【讨论】:

    • 也许 Marcus 可以帮助 wordsmith 这个
    • @AsConfused,是的,我想是的。
    【解决方案4】:

    您的锁机制需要允许以递归方式获取锁(仅限同一线程),通常称为reentrantlockMonitor 内部类)。

    同一个线程在不阻塞的情况下多次调用 Enter 是合法的;但是,在等待对象的其他线程解除阻塞之前,必须调用相同数量的 Exit 调用。

    另见Recursive / nested locking in C# with the lock statementRe-entrant locks in C#

    正如 Henk Holterman 在评论中指出的那样,Monitor 类已经是可重入的。而lock 语句正在管理对基础Monitor 类的正确数量的EnterExit 调用。

    ReaderWriterLockSlim 类是锁定机制的一个示例,可以在reentrantnon-reentrant 之间进行选择。见https://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim(v=vs.110).aspx

    var rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

    将您的 lock { ... } 替换为

    ReaderWriterLockSlim rwLock = 
        new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
    
    ...
    
    try 
    {
        rwLock.EnterWriteLock();
        // Does something
    }    
    finally 
    {
        rwLock.ExitWriteLock();
    }
    

    ```

    【讨论】:

    • 评论为什么“这个答案没用”会对我很好和有帮助。
    • 您的第一段开始正常,但随后您得出错误的结论。看看你引用的文字,lock(){} 以这里需要的简单方式重入。无需解决方法。
    • 我又读了一遍,你是对的。 Lock/Monitor 已经是可重入的
    【解决方案5】:

    您编写的代码是正确的。

    因为按照微软的说法,一旦调用被获取,即使程序在同一个流程中调用lock,也不会因为lock已经在线程中而被阻塞。 该代码的工作方式如下。

    1. 调用“MethodA”-->获取锁-->调用“MethodB”(不会因为线程已经获取锁而被阻塞)并且执行将完成。

    2. 在从另一个线程的先前执行之间调用“MethodB”,执行将被阻塞,因为锁是第一个线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多