如何在C#中找出死锁并防止它

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15361810/
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-10 16:30:42  来源:igfitidea点击:

How to find out deadlock and prevent it in C#

c#asp.net.netc#-4.0deadlock

提问by Learner

I had an interview just 5 minutes back, I didn't answer 3 questions, could someone please help me.

我在 5 分钟前接受了一次采访,我没有回答 3 个问题,有人可以帮助我。

Question:

题:

How to look for deadlock scenarios in Multithreaded application function and prevent it ?

如何在多线程应用程序功能中寻找死锁场景并防止它?

Answer I gave:

我给出的答案:

I gave definition of deadlock and lock, mutex, monitor, semaphore. He told me, that these are tools, but how to look for a deadlock scenario as because when we use these tools blindly, it costs the performance he said :(

我给出了死锁和锁、互斥锁、监视器、信号量的定义。他告诉我,这些都是工具,但如何寻找死锁场景,因为当我们盲目使用这些工具时,会降低性能,他说:(

Please help me understand this.

请帮助我理解这一点。

采纳答案by Coral Doe

Performance analysis tools can be also helpful in identifying deadlocks, among others. This question will provide some insight in this topic: C#/.NET analysis tool to find race conditions/deadlocks.

性能分析工具还有助于识别死锁等。此问题将提供有关此主题的一些见解:C#/.NET analysis tool to find Race conditions/deadlocks

Visual analysis of the code and the proper using of locks is useful also (you should be able to detect potential problems in code while inspecting it), but can be very difficult for complex applications. Sometimes the deadlocks are visible only when you run the code, not simply by inspecting the code.

代码的可视化分析和锁的正确使用也很有用(您应该能够在检查代码时检测到代码中的潜在问题),但对于复杂的应用程序可能非常困难。有时死锁仅在您运行代码时才可见,而不仅仅是通过检查代码。

I don't know too much of your interviewer. Some may want to see how much you know of locking standards/guideliness, some may want to see if you know how to use your tools, some may want both. In the company I work at, for example, the use of tools (expecially the ones we already own and use) is highly appreciated. But that does not imply one should not have the skills that would prevent coding deadlocks in the first place.

我不太了解你的面试官。有些人可能想知道您对锁定标准/指南了解多少,有些人可能想看看您是否知道如何使用您的工具,有些人可能想要两者兼而有之。例如,在我工作的公司中,使用工具(尤其是我们已经拥有和使用的工具)受到高度赞赏。但这并不意味着人们不应该首先拥有防止编码死锁的技能。

Locking something just for the sake of locking affects performance, as thread wait for each other. You have to analyse the workflow to determine what really needs to be locked, when, with what type of lock (simple lockor maybe a ReaderWriterLockSlim). There are many typical ways to prevent deadlock.

仅仅为了锁定而锁定某些东西会影响性能,因为线程相互等待。您必须分析工作流程以确定真正需要锁定什么、何时锁定、使用什么类型的锁定(简单lock或可能是ReaderWriterLockSlim)。有许多典型的方法可以防止死锁。

For example when using ReaderWriterLockSlimyou can use a timeout to prevent deadlocks (if you wait to much, you abort aquiring the lock)

例如,在使用时,ReaderWriterLockSlim您可以使用超时来防止死锁(如果等待时间过长,则会中止获取锁)

if (cacheLock.TryEnterWriteLock(timeout))
{
...
}

And you should be able to suggest such timeouts.

你应该能够建议这样的超时。

At such a question I would expect at least a mention of the classic case of deadlocks, like badly use of nested locks (you should be able to know can you avoid them, why they are bad, etc.).

在这样的问题上,我希望至少提到死锁的经典案例,例如嵌套锁的严重使用(您应该能够知道是否可以避免它们,它们为什么不好等)。

The subject is very big... you can go on and on about this. But without definitions. Knowing what a lock is and knowing to use locks/semaphores/mutex in large scale multi-threading applications are 2 different things.

这个话题非常大……你可以继续讨论这个。但没有定义。知道什么是锁和知道在大规模多线程应用程序中使用锁/信号量/互斥锁是两件不同的事情。

回答by Kna?is

The simplest solution for this problem would be to always sleep/wait with a big enough timeout. If that timeout happens you know that something took way longer than it should have and you have a good chance of a deadlock or another bug.

这个问题的最简单的解决方案是总是在足够大的超时时间内休眠/等待。如果发生超时,您就会知道某些事情花费的时间比应有的时间长,并且很可能会出现死锁或其他错误。

Mutex m; // similar overloads exist for all locking primitives
if (!m.WaitOne(TimeSpan.FromSeconds(30)))
    throw new Exception("Potential deadlock detected.");

When WaitOnereturns falseit will have waited for 30 seconds and the lock still would not have been released. If you know that all locked operations should complete within milliseconds (if not, then just increase the timeout), then this is a very good indication that something went badly.

WaitOne返回时false,它将等待 30 秒并且锁仍然不会被释放。如果您知道所有锁定的操作都应该在几毫秒内完成(如果不是,那么只需增加超时时间),那么这是一个非常好的迹象,表明某些事情发生了糟糕的事情。

回答by devshorts

I think the interview is asking you a trick question. If you could use static analysis to prevent deadlock... nobody would have deadlock!

我认为面试是在问你一个棘手的问题。如果您可以使用静态分析来防止死锁......没有人会死锁!

Personally, when I look for deadlock I start by finding functions where the critical section spans more than the function call. For example

就我个人而言,当我寻找死锁时,我首先查找临界区跨越函数调用的函数。例如

void func(){
    lock(_lock){
        func2();
     }
}

It's not really clear what func2is doing. Maybe it dispatches an event on the same thread, which would mean that event is still part of the critical section. Maybe it then locks on a differentlock. Maybe it dispatches into the threadpool and no longer is re-entrant because its now on a different thread! These kinds of places are where you can start to see deadlock scenarios happening: when you have multiple non-reentrant lock locations.

目前还不清楚func2在做什么。也许它在同一个线程上调度一个事件,这意味着该事件仍然是临界区的一部分。也许它然后锁定在不同的锁上。也许它分派到线程池中并且不再是可重入的,因为它现在在不同的线程上!在这些地方,您可以开始看到死锁场景的发生:当您有多个不可重入的锁位置时。

Other times, when tracing deadlock scenarios, I backtrack and I try and find where are all the threads created. I give thought to each function and where it can actually be running. If you aren't sure, adding in logging to log where the function call came from can also help.

其他时候,在跟踪死锁场景时,我会回溯并尝试找到创建的所有线程的位置。我考虑了每个功能以及它可以实际运行的位置。如果您不确定,添加日志以记录函数调用的来源也有帮助。

You can also avoid deadlocks by using lock free data structures (but those require just as much though to use). You want to minimize your access to the lock free structure because each time you access it it can change.

您还可以通过使用无锁数据结构来避免死锁(但那些需要同样多的使用)。您希望尽量减少对无锁结构的访问,因为每次访问它时它都可能发生变化。

As mentioned in another answer, you can use mutexes with timeouts, but that isn't guaranteed to always work (what if your code needs to work longer than the timeout?). It was mentioned in another comment that this is maybe what the interviewer was asking for. I find that in production this isn't really a good idea. Timeouts vary all the time, maybe something took longer than expected to run and hit a timeout. I think its better to let it deadlock, take a process dump, then find exactly what was holding the locks and fix the problem. Of course, if your business requirements can't allow that, then you can use this as part of a defensive coding strategy along with smart lock placement choices.

正如另一个答案中提到的,您可以将互斥锁与超时一起使用,但这并不能保证始终有效(如果您的代码需要比超时工作更长时间怎么办?)。在另一条评论中提到,这可能是面试官要求的。我发现在生产中这不是一个好主意。超时一直在变化,也许有些东西运行时间比预期的要长并达到超时。我认为最好让它死锁,进行进程转储,然后确切地找到持有锁的内容并解决问题。当然,如果您的业务需求不允许这样做,那么您可以将其用作防御性编码策略的一部分以及智能锁放置选择。

I don't agree with your interview that locks alwaysadd a huge performance problem. Uncontended locks/mutexes/etc first test as a spinlock before handing off to the OS and spinlocks are cheap.

我不同意你的采访,即锁总是会增加一个巨大的性能问题。无竞争锁/互斥锁/等在移交给操作系统之前首先作为自旋锁进行测试,自旋锁很便宜。

In general, the best way to avoid deadlock is to understand your program flow. Each time you introduce a new lock object think about where it is used and what uses it down the chain.

通常,避免死锁的最佳方法是了解您的程序流程。每次引入一个新的锁对象时,请考虑在何处使用它以及在链中使用它的内容。

回答by Ga???

It sounds like you had problems explaining how deadlocks can occur and how they can be prevented.

听起来您在解释死锁如何发生以及如何防止死锁时遇到了问题。

A deadlock occurs when each thread (minimum of two) tries to acquire a lock on a resource already locked by another. Thread 1 locked on Resources 1 tries to acquire a lock on Resource 2. At the same time, Thread 2 has a lock on Resource 2 and it tries to acquire a lock on Resource 1. Two threads never give up their locks, hence the deadlock occurs.

当每个线程(最少两个)尝试获取已被另一个线程锁定的资源的锁时,就会发生死锁。锁定资源 1 的线程 1 尝试获取资源 2 的锁。同时,线程 2 拥有资源 2 的锁,并尝试获取资源 1 的锁。两个线程从不放弃它们的锁,因此死锁发生。

The simplest way to avoid deadlock is to use a timeout value. The Monitor class (system.Threading.Monitor) can set a timeout during acquiring a lock.

避免死锁的最简单方法是使用超时值。Monitor 类(system.Threading.Monitor)可以在获取锁期间设置超时。

Example

例子

try{
    if(Monitor.TryEnter(this, 500))
    {
        // critical section
    }
}
catch (Exception ex)
{

}
finally
{
    Monitor.Exit();
}

Read More

阅读更多