2015-07-04 71 views
1

所以我必须与所有使用,以防止奇怪的事情发生了锁定的几个方法的类当有人使用我的多线程类的访问它的一个实例:多线程和锁定(线程安全的操作)

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()当前锁定了更衣柜对象,所以这不起作用。

我要让MethodB()公开访问,这样你就可以手动调用它需要的时候,但我不希望它同时MethodA()正在做的事情来使用(这就是为什么我使用的是更衣室的对象)。

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

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

该解决方案可能非常容易,我只是没有看到它。

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

+0

我删除了java标记。 –

+0

所以:欢迎来到StackOverflow!我认为你的问题写得非常清楚,出色。我们不喜欢“谢谢你”的短语(他们只是分散注意力),所以我从你的问题中删除了一个。 –

+0

为什么b lock locker会因为所描述的困境而玩弄? – Drew

回答

0

锁定禁止你想要做的 - 这是它的目的。

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

+0

是的,我一直在考虑创建一个可以被他们两个访问的私有方法,只是不确定程序员的角度是否可以,因为我可能需要创建很多私有方法,因为我有很多公共方法,都在我的应用程序中使用锁定(在编程方面我仍然有点无经验)。谢谢你的帮助! (我希望可以在评论中说“谢谢”)。 – Minegem

+0

好吧,只是不要垃圾邮件:)特别是与您的问题或答案的讨论,这是绝对没问题。 –

0

这里您有竞争条件:它使数据不正确。我想方法的写入字符串类型的静态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. 
+0

也许马库斯可以帮助这个字词 – AsConfused

+0

@AsConfused,是的,我认为是。 – hungndv

2

一个简单的解决方案是创建一个包含什么MethodB确实可以通过MethodA者和被调用另一个公共MethodB

一个 私人方法

私人MethodB不锁定,只有公众的做。

例如:

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(); 
     } 
    } 
} 

P.S.

我觉得很明显你和其他人为什么你的代码有点设计来造成死锁。


更新

显然lock(object) {}re-entrant在评论中指出,如此明显的僵局是连一个也没有。

0

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

对于同一个线程调用不止一次输入而不阻塞它是合法的;然而,在等待对象的其他线程将被解除阻塞之前,必须调用相同数量的Exit调用。

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

正如评论所指出的亨克Holterman,该Monitor类是已经折返。 lock声明正在管理EnterExit正确金额的Monitor类调​​用。

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(); 
} 

```

+0

评论为什么“这ansewer没有用”会很好,对我有帮助。 –

+0

你的第一段开始确定,但是你得出了错误的结论。看看你引用的文本,'lock(){}'可以以这里需要的简单方式重入。无需解决方法。 –

+0

我再读一遍,你是对的。锁定/监视器已经重入 –

0

的代码写的,你是正确的。

因为根据微软的说法,即使程序调用锁定在同一个流程中,一旦获得调用,它将不会被阻塞,因为线程已经锁定了。代码如下工作。

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

  2. 从另一个线程执行前一个执行过程中调用“MethodB”,由于第一个线程的锁定,执行将被阻止。