多线程调试技术多线程、技术

2023-09-03 09:50:27 作者:时光时光你慢慢走

我想知道是否有人知道调试技术为多线程应用程序的一个很好的调查。理想情况下,我在寻找一个基于案例分析:死锁,饥饿,损坏的共享状态,...

I was wondering if anyone knows of a nice survey of debugging techniques for multithreaded applications. Ideally, I'm looking for a case-based analysis: deadlocks, starvation, corrupted shared state, ...

.Net的,或一般。

.Net specific, or generic.

推荐答案

我不知道的,解决你在找什么文章或书籍,所以这里是我从12年多线程调试的经验教训的窗口(非托管和托管)。

I'm not aware of an article or book that addresses what you're looking for, so here's my "lessons learned" from 12 years of multithreaded debugging on Windows (both unmanaged and managed).

正如我在我的评论说,我大部分的多线程调试实际上是通过手动code做了检讨,寻找这些问题的。

As I stated in my comment, most of my "multithreaded debugging" is actually done via a manual code review, looking for these issues.

死锁和损坏共享状态

文件锁层次(无论是为了什么共享的状态,他们保护) ,并确保它们是一致的。这解决了大多数死锁问题,降低损坏共享状态的问题。

Document lock hierarchies (both the order and what shared state they protect), and ensure they're consistent. This solves most deadlock problems and corrupted shared state problems.

(注:以上为锁层次结构的链接是指由Herb Sutter的一个布斯博士的文章,他写了一整个系列的有效并发的文章,我强烈建议)。

(Note: the link above for "lock hierarchies" refers to a Dr. Dobbs article by Herb Sutter; he's written a whole series of Effective Concurrency articles that I highly recommend).

更多关于死锁

使用 RAII对所有同步。这确保了锁被释放在例外的面貌。 preFER锁定语句来尝试/最后。

Use RAII for all synchronization. This ensures that locks are released in the face of exceptions. Prefer the "lock" statement to try/finally.

(注意,RAII在.NET取决于的IDisposable ,不是的Finalize ,并假定客户端code会正确使用使用块)。

(Note that RAII in .NET depends on IDisposable, not Finalize, and assumes that the client code will correctly use a using block).

饥饿

删除线程优先级的任何修改。正确的优先级实际上是一个有点违反直觉:这是最好给线程的最多的工作做一个较低的优先级,并给予较高的优先级是我的线程/ O限制(包括UI线程)。由于Windows自动执行此操作(请参见 Windows内部),实在没有理由为code涉足于所有的。

Remove any modifications of thread priorities. Correct prioritization is actually a bit counter-intuitive: it is best to give the thread with the most work to do a lower priority, and give higher priorities to threads that are I/O bound (including the UI thread). Since Windows does this automatically (see Windows Internals), there's really no reason for the code to get involved at all.

一般

删除已写入内部所有无锁code。它几乎可以肯定含有微妙的错误。使用.NET 4 无锁收藏并同步对象,或更改code是基于锁

Remove all lock-free code that was written in-house. It almost certainly contains subtle bugs. Replace it with .NET 4 lock-free collections and synchronization objects, or change the code to be lock-based.

同步使用更高层次的概念。该任务并行库和的统一取消在.NET 4中删除pretty的多少需要任何的直接使用的ManualResetEvent 显示器旗语等。

Use higher-level concepts for synchronization. The Task Parallel Library and unified cancellation in .NET 4 remove pretty much any need for direct usage of ManualResetEvent, Monitor, Semaphore, etc.

有关并行使用更高层次的概念。该 TPL和PLINQ 在.NET 4内置了自动平衡算法完整的智能分区和工作窃取队列自动提供最佳的并行化。对于一些罕见的情况下,该自动并行化是​​次优的,无论是TPL和PLINQ露出一个巨大的可修改旋钮(自定义分区方案,长期运行的操作标志等)。

Use higher-level concepts for parallelization. The TPL and PLINQ in .NET 4 have built-in self-balancing algorithms complete with intelligent partitioning and work-stealing queues to provide optimum parallelization automatically. For the few rare cases that the automatic parallelization is sub-optimal, both TPL and PLINQ expose a huge number of tweakable knobs (custom partitioning schemes, long-running operation flags, etc).

还有一个技巧,我发现,有它的方法调用不同的线程的任何类有用:文件,它的方法哪个线程上运行。通常,这被添加作为注释的方法的顶部。确保每个方法仅在一个已知的线程上下文中运行(例如,在UI线程在线程池线程或上专用的后台线程或)。没有一种方法,应该说在任何线程,除非你正在写一个同步类(如果你正在写一个同步类,问问自己是否真的应该这样做)。

There is one more technique I've found useful for any class that has its methods called by different threads: document which methods run on which threads. Usually, this is added as a comment to the top of the method. Ensure each method only runs in a known thread context (e.g., "on a UI thread" or "on a ThreadPool thread" or "on the dedicated background thread"). None of the methods should say "on any thread" unless you're writing a synchronization class (and if you're writing a synchronization class, ask yourself if you really should be doing that).

最后,命名您的线程。这有助于使用VS调试器时很容易区分。 .NET通过 Thread.Name 属性支持这一点。

Lastly, name your threads. This helps easily distinguish them when using the VS debugger. .NET supports this via the Thread.Name property.