C#/MSTEST中基于信号量的业务逻辑的多线程测试

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

在我的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 (!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
语句的执行),因此,这是您需要小心的事情,使用锁(但不是同步阻止锁)是一种正常的方法。