我有一个看起来像这样的方法:
void Foo ()
{
bool flag;
do
{
flag = false;
var check = CheckSomething();
if(check)
{
DoSomething();
flag = true;
}
}
while(flag);
}
目前我正在使用以下代码片段(在许多工作线程中执行)调用该方法:
Bar(); // this method may affect the outcome of CheckSomething()
ThreadPool.QueueUserWorkItem(state => Foo());
CheckSomething()
价格昂贵,因此我不希望Foo()
更频繁地被调用是否有保证安全的方式来调用Foo()
当且仅当它尚未执行并且在退出之前打电话给CheckSomething()
?
答案 0 :(得分:2)
如果我理解正确,您希望阻止Foo
运行,如果它已经被执行了。似乎你可以使用Monitor。
private object fooLock = new object();
void Foo ()
{
// Try to acquire the lock
if (!Monitor.TryEnter(fooLock))
{
// Some other thread is already in this method.
return;
}
bool flag;
do
{
flag = false;
var check = CheckSomething();
if(check)
{
DoSomething();
flag = true;
}
}
while(flag);
// release the lock
Monitor.Exit(fooLock);
}
(对于那些想知道为什么我没有将Monitor.Exit
放在finally
条款中的人,请参阅Eric Lippert的Locks and exceptions do not mix。)
这不会阻止Foo
被调用,但它会阻止多个线程进入循环,因此CheckSomething
不能从Foo
内同时调用。< / p>
您的要求有点模糊,因此可能无法完全按照您的要求进行操作。如果一个线程已经调用CheckSomething
并且已经返回false
但尚未退出,并且另一个线程进入该方法,那么您想要发生什么有些含糊不清。处理这种竞争条件会有点棘手。
答案 1 :(得分:0)
在Servy的评论的帮助下,我现在设法通过版本化我的共享内存来解决问题:
Bar
都会增加底层共享内存的版本Bar
会返回我传递给Foo
Foo
将当前版本传递给CheckSomething
- 包装器CheckSomething
- 如果给定版本小于共享内存的当前版本,则wrapper立即返回false - &gt; Foo
退出唯一的问题是在短时间内拨打Bar
的次数过多会使Foo
方法挨饿,这就是为什么我无论如何都要运行它,如果版本差异超过一个常数值(例如50)。
再次感谢您的帮助!