C# 如何在外部类的每个方法调用周围自动添加锁?
我有一个来自外部开发人员的dll,它是基于C的,并且周围有一个C#包装器。单个调用不是线程安全的,根据开发人员的说法,我需要自己锁定每个调用 我开始在其中一些代码中添加锁,并注意到这是一个很难实现的问题(让人麻木的代码片段复制粘贴),并导致我的代码变得非常难看和不可读。我现在想知道是否有更简单的方法。现在看起来是这样的:C# 如何在外部类的每个方法调用周围自动添加锁?,c#,C#,我有一个来自外部开发人员的dll,它是基于C的,并且周围有一个C#包装器。单个调用不是线程安全的,根据开发人员的说法,我需要自己锁定每个调用 我开始在其中一些代码中添加锁,并注意到这是一个很难实现的问题(让人麻木的代码片段复制粘贴),并导致我的代码变得非常难看和不可读。我现在想知道是否有更简单的方法。现在看起来是这样的: lock (LockObject) Wrapper.DeleteAllSequences(); lock (LockObject) Wrapper.Upload
lock (LockObject)
Wrapper.DeleteAllSequences();
lock (LockObject)
Wrapper.UploadSequence();
lock (LockObject)
Wrapper.StartSequence();
必须有某种构造自动在我从包装器调用的每个方法周围添加一个锁,而不是每次都要求我手动执行此操作。正如@JHBonarius所建议的,您可以像这样重构,使用一个方法对应一个目标方法签名:
public void CallLocked(Action method)
{
if (method != null)
lock (LockObject)
method();
}
用法:
CallLocked(Wrapper.DeleteAllSequences);
或:
您需要创建与需要调用的不同方法签名一样多的CallLocked
重载
例如,由于没有语言关键字,因此即使这似乎是一个糟糕的解决方案,您也只能这样做:
threadlock Wrapper.DeleteAllSequences();
我写它似乎是因为在CallLocked
中,您可以添加任何try catch
和其他您想要的流控制管理
enum ExceptionBehavior { Hide, Show, Raise };
public void CallLocked(Action method,
ExceptionBehavior exceptionBehavior = ExceptionBehavior.Raise)
{
if (method != null)
lock (LockObject)
try
{
method();
}
catch ( Exception ex )
{
switch ( exceptionBehavior )
{
case ExceptionBehavior.Hide;
break;
case ExceptionBehavior.Show;
MessageBox.Show(...);
break;
case ExceptionBehavior.Raise;
throw;
}
}
}
当然,您可以添加一些行为,如
HideAndLog
,ShowAndLog
,RaiseAndLog
。。。并使用一个全局变量来设置默认行为。我会说:要么更改包装器,要么围绕包装器构建一个包装器……没有理由这么做。您需要在试图从多个线程访问该方法的代码周围设置一个锁。您需要确定哪些方法也可以在单个线程中运行-如果多个线程依次调用DeleteAllSequences()
或uploadSequence()
该怎么办?使用多个锁将允许这样做。我怀疑这是你想要的。首先,你有多个线程吗?您正在构建什么样的应用程序?图书馆做什么?如果需要在单个线程中运行这3个方法,可以使用lock(xx){Wrapper.DeleteAllSequences();Wrapper.UploadSequence();Wrapper.UploadSequence();}
。另一方面,通过将相关代码放在使用自己线程的单独类中,可以确保只有一个线程可以访问该库。或者,如果您可以在一个调用中组合所有库操作,您可以使用一个ActionBlock,它在每个输入消息中只使用一个线程default@JHBonarius是的,我就是这么想的,但我不想这么做:D希望有一个我不知道的结构可以让我跳过它work@DanielM你所要求的并不存在,正如我所知,因此您必须像使用calllock
一样实现它。这与使用lock
没有什么不同,并且不会防止多个线程从中调用方法sequence@PanagiotisKanavos也许你不理解OP的问题。看看你的代码和OP的代码。区别在于两个字符。如果使用lock(x)
此代码实际上比原始代码更糟糕。如果你真的不想我投反对票,你可以写lock(x){Wrapper.DeleteAllSequences();}
,但是JHBonarious建议放弃原来的包装,创建一个不需要手动锁定的更好的包装。只要将锁
放入DeleteAllSequences()
等中,就不需要手动锁了。@OlivierRogier在您的情况下,每次实际调用包装器时,我仍然需要编写CallLocked()。我的理想解决方案是“神奇地”将锁添加到包装器的每个调用中,而不必担心它。(但也不是我的反对票)
enum ExceptionBehavior { Hide, Show, Raise };
public void CallLocked(Action method,
ExceptionBehavior exceptionBehavior = ExceptionBehavior.Raise)
{
if (method != null)
lock (LockObject)
try
{
method();
}
catch ( Exception ex )
{
switch ( exceptionBehavior )
{
case ExceptionBehavior.Hide;
break;
case ExceptionBehavior.Show;
MessageBox.Show(...);
break;
case ExceptionBehavior.Raise;
throw;
}
}
}