gpt4 book ai didi

c# - 检测一个方法在没有锁的情况下被调用

转载 作者:可可西里 更新时间:2023-11-01 08:13:08 24 4
gpt4 key购买 nike

有什么方法可以检测到我的代码中的某个方法被调用,而无需在调用堆栈中的以下任何方法中使用任何锁?
目标是调试有故障的应用程序并查明某些代码段是否不是线程安全的。

最佳答案

这似乎是 AOP(面向方面​​的编程)的一个不错的用例。 AOP 的一个非常基本的总结是,它是一种处理横切关注点的方法,使代码干燥和模块化。这个想法是,如果你对一个对象的每个方法调用做一些事情(例如记录每个调用)而不是在每个方法的开始和结束添加日志,你而是继承对象并在类之外做为了不混淆其目的。

这可以通过几种方式完成,我将举两个例子。首先是手动(这不是很好,但对于小箱子可以很容易地完成)。

假设您有一个类 Doer,它有两个方法 Do 和 Other。您可以从中继承并制作

public class Doer
{
public virtual void Do()
{
//do stuff.
}

public virtual void Other()
{
//do stuff.
}
}

public class AspectDoer : Doer
{
public override void Do()
{
LogCall("Do");
base.Do();
}

public override void Other()
{
LogCall("Other");
base.Other();
}

private void LogCall(string method)
{
//Record call
}
}

如果您只关心一门类(class),这很好,但如果您必须为许多类(class)做这件事,很快就会变得不可行。对于这些情况,我建议使用类似 CaSTLeProxy 库的东西。这是一个动态创建代理来包装您想要的任何类的库。结合 IOC,您可以轻松地将每项服务包装在您的应用程序中。

这是一个使用 CaSTLeProxy 的简单示例,要点是使用 ProxyGenerator.GenerateProxy 并传入 IInterceptors 来围绕方法调用做一些事情:

    [Test]
public void TestProxy()
{
var generator = new ProxyGenerator();
var proxy = generator.CreateClassProxy<Doer>(new LogInterceptor());
proxy.Do();
Assert.True(_wasCalled);
}

private static bool _wasCalled = false;
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Log(invocation.Method.Name);
invocation.Proceed();
}

private void Log(string name)
{
_wasCalled = true;
}
}

现在,日志记录部分。我不确定你是否真的需要这个来实现无锁,短锁可能就足够了,但让我们继续思考你是否需要。

我不知道 C# 中有多少工具支持无锁操作,但我能看到的最简单的版本是使用 Interlocked 来增加一个计数器,该计数器表示在任何给定时间方法中有多少实例如果会看像这样:

        [Test]
public void TestProxy()
{
var generator = new ProxyGenerator();
var proxy = generator.CreateClassProxy<Doer>(new LogInterceptor());
proxy.Do();
Assert.AreEqual(1, _totalDoCount);
}

private static int _currentDoCount = 0;
private static int _totalDoCount = 0;
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.Method.Name == "Do")
{
var result = Interlocked.Increment(ref _currentDoCount);
Interlocked.Increment(ref _totalDoCount);
if(result > 1) throw new Exception("thread safe violation");
}


invocation.Proceed();
Interlocked.Decrement(ref _currentDoCount);
}
}

Interlocked 使用神奇的寄存器魔法来进行线程安全操作(我相信比较和交换,但我真的不知道)。如果您需要更多的上下文而不仅仅是“它发生了”。您可以使用无锁的并发堆栈或并发队列(它们也使用互锁:https://msdn.microsoft.com/en-us/library/dd997305.aspx/)。不过,我会在其中包含一个时间戳,因为我对它们的使用还不够多,无法知道它们是否 promise 按元素出现的顺序返回元素。

就像我上面说的,你可能不需要无锁操作,但这应该。我不知道这是否适合您,因为我不知道您的确切问题,但它应该为您提供一些解决此问题的工具。

关于c# - 检测一个方法在没有锁的情况下被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40169897/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com