C#/MSTEST中基于信号量的业务逻辑的多线程测试
在我的C#/Net核心项目中,我有一个方法,如C#/MSTEST中基于信号量的业务逻辑的多线程测试,c#,multithreading,.net-core,mstest,C#,Multithreading,.net Core,Mstest,在我的C#/Net核心项目中,我有一个方法,如 var MySemaphore = new SemaphoreSlim(1, 1); public async Task<RetrievalStatusReply> InitializeUpdate() { // This instruction lets routine quit if lock is taken by other thread if (!MySe
var MySemaphore = new SemaphoreSlim(1, 1);
public async Task<RetrievalStatusReply> InitializeUpdate()
{
// This instruction lets routine quit if lock is taken by other thread
if (!MySemaphore.Wait(0))
{
// if can not enter the lock
return;
}
try
{
// business logic
}
finally
{
MySemaphore.Release();
}
}
var MySemaphore=新信号量lim(1,1);
公共异步任务初始化更新()
{
//如果锁被其他线程占用,此指令允许例程退出
如果(!MySemaphore.Wait(0))
{
//如果不能进入锁
返回;
}
尝试
{
//业务逻辑
}
最后
{
MySemaphore.Release();
}
}
并希望在MsTest中使用某种多线程设置或测试实用程序库来测试其行为,例如,类似于Java的
如何为C#/Net内核编写这样的测试?测试多线程代码可能会非常混乱。我首选的方法是使用ManualResetEvents来控制执行顺序。这通常要求您通过注入测试代码或其他方式,对要测试的代码进行测试 这样的测试结果应该是一致的:
SemaphoreSlim MySemaphore = new SemaphoreSlim(1, 1);
public ManualResetEventSlim BusinessLogicReached= new ManualResetEventSlim(false);
public ManualResetEventSlim BusinessLogicWaiting = new ManualResetEventSlim(false);
public bool InitializeUpdate()
{
// This instruction lets routine quit if lock is taken by other thread
if (!MySemaphore.Wait(0))
{
// if can not enter the lock
return false;
}
try
{
BusinessLogicReached.Set();
BusinessLogicWaiting.Wait();
return true;
}
finally
{
MySemaphore.Release();
}
}
[Test]
public void RunTest()
{
var updateTask = Task.Run(InitializeUpdate);
BusinessLogicReached.Wait();
Assert.IsFalse(InitializeUpdate()); // Semaphore taken
BusinessLogicWaiting.Set();
updateTask.Wait();
Assert.IsTrue(updateTask.Result);
Assert.IsTrue(InitializeUpdate()); // Semaphore released
}
这就是说,这些类型的测试编写和维护起来很麻烦,并且不能证明一般的线程安全性,因此对多线程代码进行彻底的代码检查可能更具成本效益。为什么首先要使用信号量?您已经在使用任务和
async/await
,因此您的代码不必锁定或等待。你是想限制这种方法吗?或者只是懒洋洋地初始化一次?至于如何测试异步代码,您已经在使用任务了。您可以使用Task.Run
在一个新线程上运行一些东西,但是.NET和TPL有比Java更高级的库,比如通道、数据流、PLINQ等。不过,在这种情况下,看起来您需要懒洋洋的。如果您想用有限的DOP执行请求,或者一次执行一个,您可以使用数据流块或通道执行单个读卡器任务。对于这两个名称空间,您可以使用输入/输出缓冲。通过通道,您可以指定缓冲区已满时会发生什么情况,例如wait、discard first、discard last您还可以使用ReactiveX来限制请求。在这种情况下,尽管我怀疑您可以使用一个带有单插槽缓冲区和dropbox的通道behavior@PanagiotisKanavos这是一种非常正常的模式:async/await
允许方法在单个线程上重新进入(可以在单个线程上同时挂起多个await
语句的执行),因此,这是您需要小心的事情,使用锁(但不是同步阻止锁)是一种正常的方法。