如何获取锁在两个地方,但释放一个地方? [英] how to obtain a lock in two places but release on one place?

查看:159
本文介绍了如何获取锁在两个地方,但释放一个地方?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是在c#新手。我需要2方法来获取锁,但是在一个方法释放。 ?请问这项工作。



 公共无效obtainLock(){
Monitor.Enter(lockObj);
}

公共无效obtainReleaseLock(){
锁(lockObj){
doStuff
}
}

特别是我可以叫 obtainLock 然后 obtainReleaseLock ?是DOUBLELOCK允许在C#中?这两个方法总是从同一个线程调用,但 lockObj 在另一个线程同步使用。



< STRONG> UPD:你怎么看待这样的代码什么都意见后?它是理想的?



 公共无效obtainLock(){
如果(needCallMonitorExit == FALSE){
Monitor.Enter(lockObj);
needCallMonitorExit = TRUE;
}
// doStuff
}

公共无效obtainReleaseLock(){
尝试{
锁(lockObj){
// doAnotherStuff
}
} {最后
如果(needCallMonitorExit ==真){
needCallMonitorExit = FALSE;
Monitor.Exit(lockObj);
}
}
}


解决方案

是的,锁是可重入,所以一个电话就可以双锁(你的那句)的 lockObj 。但是请注意,它需要,因为它是采取公布确切多次;你需要确保有一个相应的RELEASELOCK匹配ObtainLock。



我这样做,不过,建议更容易让调用锁(...)的一些属性,你揭露,虽然:

 公共对象{为SyncLock获得{返回lockObj; }} 

现在调用者可以的(而不是 obtainLock()):

 锁(something.SyncLock){
// ...
}

更容易得到正确的。因为这是同一个底层 lockObj 在内部使用,这种同步对任何使用,即使 obtainReleaseLock (等)使用的的代码,锁定,以防的SyncLock






通过上下文更清晰(评论),似乎可能等待脉冲是办法做到这一点:

 无效SomeMethodThatMightNeedToWait(){
锁(lockObj){
如果(needSomethingSpecialToHappen){
Monitor.Wait(lockObj);
// ^^^此***释放***锁(需要然而多次),和
//进入未决队列;当*另一个*线程脉冲,它
//进入就绪队列;当锁*可用*,它
//重新获取锁(回多次举行了它
//以前)和恢复工作,
}
//做了一些工作,快乐的东西特别的事情发生,和
//我们有锁
}
}
无效SomeMethodThatMightSignalSomethingSpecial(){
锁(lockObj){
//做的东西
Monitor.PulseAll(lockObj);
// ^^^此招式** **所有从挂起队列项目就绪队列
//注意也有脉冲(...),它移动的*单*项目
}
}

请注意,当使用等待你可能想使用接受超时超负荷,避免永远等待;还要注意的是很常见的循环和再验证,例如:

 锁(lockObj){
在(needSomethingSpecialToHappen){
Monitor.Wait(lockObj);
//在这一点上,我们知道我们被脉冲,但也许另一个等待
//线程打我们吧!重新检查车况,并继续;这(中止时,和
//记得做PulseAll())可能
//也可以检查一些中止状态的好地方
}
//做了一些工作,快乐的东西特别的事情发生,我们必须锁定
}


i'm newbie in c#. I need to obtain lock in 2 methods, but release in one method. Will that work?

public void obtainLock() {
    Monitor.Enter(lockObj);
}

public void obtainReleaseLock() {
    lock (lockObj) {
        doStuff
    }
}

Especially can I call obtainLock and then obtainReleaseLock? Is "doubleLock" allowed in C#? These two methods are always called from the same thread, however lockObj is used in another thread for synchronization.

upd: after all comments what do you think about such code? is it ideal?

public void obtainLock() {
    if (needCallMonitorExit == false) {
        Monitor.Enter(lockObj);
        needCallMonitorExit = true;
    }
    // doStuff
}

public void obtainReleaseLock() {
    try {
        lock (lockObj) {
            // doAnotherStuff
        }
    } finally {
        if (needCallMonitorExit == true) {
            needCallMonitorExit = false;
            Monitor.Exit(lockObj);
        }
    }
}

解决方案

Yes, locks are "re-entrant", so a call can "double-lock" (your phrase) the lockObj. however note that it needs to be released exactly as many times as it is taken; you will need to ensure that there is a corresponding "ReleaseLock" to match "ObtainLock".

I do, however, suggest it is easier to let the caller lock(...) on some property you expose, though:

 public object SyncLock { get { return lockObj; } }

now the caller can (instead of obtainLock()):

lock(something.SyncLock) {
     //...
}

much easier to get right. Because this is the same underlying lockObj that is used internally, this synchronizes against either usage, even if obtainReleaseLock (etc) is used inside code that locked against SyncLock.


With the context clearer (comments), it seems that maybe Wait and Pulse are the way to do this:

void SomeMethodThatMightNeedToWait() {
    lock(lockObj) {
        if(needSomethingSpecialToHappen) {
            Monitor.Wait(lockObj);
            // ^^^ this ***releases*** the lock (however many times needed), and
            // enters the pending-queue; when *another* thread "pulses", it
            // enters the ready-queue; when the lock is *available*, it
            // reacquires the lock (back to as many times as it held it 
            // previously) and resumes work
        }
        // do some work, happy that something special happened, and
        // we have the lock
    }
}
void SomeMethodThatMightSignalSomethingSpecial() {
    lock(lockObj) {
        // do stuff
        Monitor.PulseAll(lockObj);
        // ^^^ this moves **all** items from the pending-queue to the ready-queue
        // note there is also Pulse(...) which moves a *single* item
    }
}

Note that when using Wait you might want to use the overload that accepts a timeout, to avoid waiting forever; note also it is quite common to have to loop and re-validate, for example:

lock(lockObj) {
    while(needSomethingSpecialToHappen) {
        Monitor.Wait(lockObj);
        // at this point, we know we were pulsed, but maybe another waiting
        // thread beat us to it! re-check the condition, and continue; this might
        // also be a good place to check for some "abort" condition (and
        // remember to do a PulseAll() when aborting)
    }
    // do some work, happy that something special happened, and we have the lock
}

这篇关于如何获取锁在两个地方,但释放一个地方?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆