C#如何检测一个对象已经被锁定

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12033725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 20:08:48  来源:igfitidea点击:

C# How to detect an object is already locked

c#multithreading.net-4.0locking

提问by hwcverwe

How can I detect whether an object is locked or not?

如何检测对象是否被锁定?

Monitor.TryEnter(as described in Is there a way to detect if an object is locked?) does not work for me because it locks the object if it is not locked.

Monitor.TryEnter(如Is there a way to detect if an object is locked? 中所述)对我不起作用,因为如果对象未锁定,它会锁定对象。

I onlywant to check if it is locked and somewhere else in my code I will use the Monitorclass to lock the object.

只是想检查,如果它被锁定,其他地方在我的代码,我将使用Monitor类锁定对象。

I know it is possible to use for example an boolean field (for example private bool ObjectIsLocked) but what to detect it using the lock-object itself.

我知道可以使用例如布尔字段(例如private bool ObjectIsLocked),但是可以使用锁定对象本身来检测它。

The example code below shows what I want to do:

下面的示例代码显示了我想要做什么:

private static object myLockObject = new object();

private void SampleMethod()
{
    if(myLockObject /*is not locked*/) // First check without locking it
    {
        ...
        // The object will be locked some later in the code
        if(!Monitor.TryEnter(myLockObject)) return;

        try
        {

            ....
        }
        catch(){...}
        finally
        {
            Monitor.Exit(myLockObject);
        }
    }
}

采纳答案by Marcelo De Zen

You're doing it wrong. If you don't have the lock on the object you can't check if it is locked (and if you have the lock you will know in advance). You can "ask" "is locked?" and get a "not" as response, then on the next nanosecond another thread can take the lock and your program will enter in a corrupted state. This simply is not the way to go on multithreaded apps and the reason why .NET does not have a Monitor.IsLockedmethod. If your code needs to check the lock before acquire it so you have a design problem. Trying to solve it with unprotected flags is a poor solution that is guaranteed by 100% of chance that will not work.

你做错了。如果您没有锁定对象,则无法检查它是否已锁定(如果您拥有锁定,您将提前知道)。你可以“问”“被锁了吗?” 并得到一个“not”作为响应,然后在下一个纳秒内另一个线程可以获取锁并且您的程序将进入损坏状态。这根本不是多线程应用程序的方法,也是 .NET 没有Monitor.IsLocked方法的原因。如果您的代码需要在获取锁之前检查锁,那么您就有了设计问题。尝试使用不受保护的标志来解决它是一个糟糕的解决方案,保证 100% 的机会不会起作用。

Anyway, do not use a boolvar to signal multi-thread is lockedstate (because you can have the same problem, you read "false" and 1 nanosecond later another thread will write "true" to it). Use Interlock.CompareExchange.

无论如何,不​​要使用boolvar 来表示多线程处于锁定状态(因为您可能遇到同样的问题,您读取“false”,1 纳秒后另一个线程将向其写入“true”)。使用Interlock.CompareExchange.

private static int _lockFlag = 0; // 0 - free

if (Interlocked.CompareExchange(ref _lockFlag, 1, 0) == 0){
   // only 1 thread will enter here without locking the object/put the
   // other threads to sleep.

   Monitor.Enter(yourLockObject); 

   // free the lock.
   Interlocked.Decrement(ref _lockFlag);
}

You'll see that you'll need to change the _lockFlag on every placewhere a lock to your object could be aquired. In other words, you'll construct a custom lock system around the native one.

您将看到您需要在可以获取对象锁定的每个位置更改 _lockFlag 。换句话说,您将围绕原生锁定系统构建一个自定义锁定系统。

回答by David Schwartz

If you want to ensure the object is still lockable later on, just call TryEnterand hold the lock the whole time. Otherwise, if you want to try to lock the object later, just call TryEnterand immediately unlock it if it's locked.

如果您想确保该对象稍后仍可锁定,只需TryEnter在整个过程中调用并保持锁定即可。否则,如果您想稍后尝试锁定该对象,只需调用TryEnter并在它被锁定时立即解锁它。

回答by Pete

Monitor.IsEnteredshould do the trick.

Monitor.IsEntered应该可以解决问题。

Edit: I just re-read the documentation, and it says:

编辑:我只是重新阅读了文档,它说:

Determines whether the current thread holds the lock on the specified object.

确定当前线程是否持有指定对象的锁。

So that is not sufficient, as you would probably like to know if a different thread holds a lock?

所以这还不够,因为您可能想知道不同的线程是否持有锁?

回答by Andrey Taptunov

Techincally you can check for object's Sync Block Indexfield which has an index of associated lazily allocated structure in Sync Blocks array- every object has this field and every object, which used for synchronziation, has this field set. These structures are used to coordinate thread synchronization. However, I highly doubt that you'll be able to access this information without Profiling API.

从技术上讲,您可以检查对象的同步块索引字段,该字段在同步块数组中具有关联延迟分配结构的索引- 每个对象都有这个字段,并且每个用于同步的对象都设置了这个字段。这些结构用于协调线程同步。但是,我非常怀疑您是否能够在不使用Profiling API 的情况下访问这些信息。

回答by IvoTops

There is no way to do this with the Monitor class in C#

C# 中的 Monitor 类无法做到这一点

Just use;

只需使用;

    var lockedBySomeoneElse = !Monitor.TryEnter(obj);
    if (!lockedBySomeoneElse) Monitor.Exit(obj);
    // the variable 'lockedBySomeoneElse' has the info you want

Other locks like readerwriterlockslim do not really help. That one can tell you how may readers there are, but not if there is a writer busy ;-(

其他像 readerwriterlockslim 这样的锁并没有真正的帮助。那个人可以告诉你有多少读者,但如果有一个作家很忙,那就不行了;-(

also if you use your own suggestion 'private bool ObjectIsLocked', which is the route I would take I think, you should use

此外,如果您使用自己的建议“private bool ObjectIsLocked”,这是我认为的路线,您应该使用

      private volatile bool ObjectIsLocked

This will make C# reflect changes to it better with multithread updates.

这将使 C# 通过多线程更新更好地反映对它的更改。

回答by Geoff Johnson

I can in no way advocate checking locks then entering code blocks. However, I found this thread while looking for a way to check a new function couldn't leave an object locked. A unit test based on Monitor.IsEntered got me exactly what I was looking for.

我绝不提倡检查锁然后输入代码块。但是,我在寻找一种检查新函数无法锁定对象的方法时发现了这个线程。基于 Monitor.IsEntered 的单元测试正是我想要的。