[英]How to implement and unit test a lock in C#
我有一个方法需要以原子方式执行一些操作,并且不应同时执行对该方法的两次调用。 这是我尝试实现一个简单的锁( SomeClass
被注册为单例):
public class SomeClass
{
private bool isRunning;
public void DoWork()
{
if (this.isRunning)
{
return;
}
try
{
this.isRunning = true;
// do some work that has to be done atomically and takes some time
}
catch (Exception e)
{
// handle exception
}
finally
{
this.isRunning = false;
}
}
}
首先这是正确的吗? 其次,我该如何单元测试呢?
你的方法的问题是你的线程可以在任何时候被中断,很多时候你的代码可能会工作,事实上,如果实际工作很重要,你的代码将在很大比例的时间内工作,但是它并不健壮,所以看看你的代码,如果this.isRunning == false
.... 并且两个线程尝试调用 DoWork ....
if (this.isRunning)
{
return;
}
// first thread gets to here, and gets context switched, then that means
// second thread will get to here also as isRunning is still false,
// but now we have two threads in this piece of code which is what we wanted to avoid.
try
{
// first and second thread will come here now....
this.isRunning = true;
// and both will go on to do work....
该框架提供了标准的 Thread 原语来阻止这种情况的发生。 因此,我已将临界区分离到一个单独的类 (JustOne) 中,以便您可以独立于您的工作代码对其进行测试。
public class JustOne
{
private Object _lock = new Object();
public bool Do(Action action)
{
bool lockTaken = false;
try
{
Monitor.TryEnter(_lock, ref lockTaken);
if (lockTaken)
{
action();
}
else
{
return false;
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(_lock);
}
}
return true;
}
}
然后你的班级看起来像
public class SomeClass
{
private readonly JustOne _work;
public SomeClass()
{
_work = new JustOne();
}
public bool DoWork()
{
return _work.Do(() =>
{
// actual work
});
}
}
现在你可以用类似的东西测试 JustOne
public void TestLock()
{
var first = new AutoResetEvent(false);
var second = new AutoResetEvent(false);
var work = new JustOne();
var t = Task.Run(() => work.Do(() =>
{
first.Set();
second.WaitOne();
}));
first.WaitOne();
Assert.False(work.Do(() => { }));
second.Set();
t.Wait();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.