重写 C# 的 Monitor.Enter 和 Monitor.Exit

发布于 2024-10-18 16:50:35 字数 830 浏览 0 评论 0原文

我正在开发一些大型多线程项目,昨天我遇到了死锁(我的第一个死锁),我通过添加 Console.WriteLine("FunctionName: Lock on VariableName") 和 Console.WriteLine("FunctionName" 来跟踪它:解锁变量名”)。添加所有这些是一项相当大的工作。

首先,该程序有一个每秒运行 2 次的主循环,该循环在主循环处理后向其他线程发出脉冲以完成其工作。现在发生的事情是,我有一个处于等待状态的线程要发出脉冲,当它发出脉冲时,它调用另一种方法,该方法也会等待发出脉冲,但脉冲已经发生,并且线程不会再次发出脉冲,直到该操作实际上已经完成了。

现在我想做的是重写 Monitor.Enter 和 Monitor.Exit 函数,而不将它们包装在类中。
我听说过很多关于反射的内容,但我不知道如何将其应用于此目的,我知道实现这一切的最简单方法是仅使用包装类,但随后 lock 关键字将不再起作用,我必须将所有锁转换为 Monitor.Enter try { } finally { Monitor.Exit },这是一项巨大的工作量。

所以我的问题是:如何重写 Monitor.Enter 和 Monitor.Exit 函数,同时保持对基本函数的访问以执行实际锁定?
如果这是不可能的:如何重写锁定语句来调用我的包装类而不是 Monitor.Enter 和 Monitor.Exit 函数?

为了清晰起见进行编辑:
我请求这个只是为了允许我在锁定发生时记录,以使调试过程更容易,这也意味着我不想创建自己的锁定机制,我只想在锁定建立时记录 /em> 以及何时发布
大多数情况下,只有当我遇到线程问题时,才会执行关闭。

I'm working on some big multi threaded project, now yesterday I had a deadlock (my first one ever), and I traced it by adding a Console.WriteLine("FunctionName: Lock on VariableName") and Console.WriteLine("FunctionName: Unlocking VariableName"). Adding all those was quite some work.

First of all, the program has a main loop that runs 2 times per second, that loop pulses some other threads to complete their work after the main loop has processed. Now what happened was that I had one thread in wait state to be pulsed, when it was pulsed it called another method that'd also wait to get pulsed, but the pulse already happened, and the thread won't pulse again until the action is actually completed.

Now what I want to do is override the Monitor.Enter and Monitor.Exit functions, without wrapping them in a class.
I've heard a lot about Reflection, but I have no idea how to apply it for this purpose, I know the easiest way to achieve it all is by just using a wrapper class, but then the lock keyword won't work anymore, and I'd have to convert all locks into Monitor.Enter try { } finally { Monitor.Exit }, that's huge amount of work.

So my question: How to override the Monitor.Enter and Monitor.Exit functions, while keeping access to the base function to do the actual lock?
And if that's impossible: How to override the lock statement to call my wrapper class instead of the Monitor.Enter and Monitor.Exit functions?

EDIT FOR CLARITY:
I request this just for allowing me to log when the locks happen, to make the debugging process easier, that also means I don't want to create my own locking mechanism, I just want to log when a lock is established and when it's released.
The close will also not be executed most of the time, only when I come across a threading problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凯凯我们等你回来 2024-10-25 16:50:35

听起来您正在寻找锁助手。 Jon Skeet 的 MiscUtil 有一些:
http://www.yoda.arachsys.com/csharp/miscutil/usage /locking.html

这个想法是用 using 语句替换 lock 语句,从而保留 try-finally 结构:

class Example
{
    SyncLock padlock = new SyncLock();

    void Method1
    {
        using (padlock.Lock())
        {
            // Now own the padlock
        }
    }      

    void Method2
    {
        using (padlock.Lock())
        {
            // Now own the padlock
        }
    }
}

关于死锁预防,库提供了一个专门的有序锁:

class Example
{
    OrderedLock inner = new OrderedLock("Inner");
    OrderedLock outer = new OrderedLock("Outer");

    Example()
    {
        outer.InnerLock = inner;
    }
}

当然,您可以扩展 Jon 的助手,或者简单地创建您自己的助手(用于日志记录目的等)。查看上面的链接以获取更多信息。

It sounds like you're looking for lock helpers. Jon Skeet's MiscUtil has some:
http://www.yoda.arachsys.com/csharp/miscutil/usage/locking.html

The idea is that you replace your lock statements with using statements and thus preserve the try-finally structure:

class Example
{
    SyncLock padlock = new SyncLock();

    void Method1
    {
        using (padlock.Lock())
        {
            // Now own the padlock
        }
    }      

    void Method2
    {
        using (padlock.Lock())
        {
            // Now own the padlock
        }
    }
}

With regards to deadlock prevention, the library offers a specialized ordered lock:

class Example
{
    OrderedLock inner = new OrderedLock("Inner");
    OrderedLock outer = new OrderedLock("Outer");

    Example()
    {
        outer.InnerLock = inner;
    }
}

Of course, you could extend Jon's helpers, or simply create your own (for logging purposes, etc). Check out the link above for more information.

ぃ双果 2024-10-25 16:50:35

别这样做!这听起来很疯狂;-)

当 2 个(或更多)线程都等待同时持有 2 个(或更多)锁时,就会发生死锁。每个线程都获得一个锁并等待另一个线程。

您通常可以重新设计代码,以便每个线程只需要一个锁 - 这使得死锁不可能发生。

如果做不到这一点,您可以让线程在无法获取第二个锁时放弃第一个锁。

Don't do it! That sounds bonkers ;-)

A deadlock occurs when 2 (or more) threads are all waiting to simultaneously hold 2 (or more) locks. And each thread gets a lock and waits for the other one.

You can often redesign your code so each thread only requires a single lock - which makes deadlock impossible.

Failing that, you can make a thread give up the first lock if it can't acquire the second lock.

吃颗糖壮壮胆 2024-10-25 16:50:35

这是一个非常糟糕的主意。我从来不需要覆盖 Monitor.Enter / Exit 或锁定来克服死锁。请考虑重新设计您的代码!
例如,使用 ManualResetEvent 进行脉冲。

That's a very bad idea. I never had to override Monitor.Enter / Exit or lock to overcome a deadlock. Please consider redesigning your code!
For example, use ManualResetEvent for the pulsing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文