C#,调用方法 - 仅在当前未调用时

时间:2013-09-09 20:14:16

标签: c# concurrency

我有一个看起来像这样的方法:

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());
  • 对我来说,在调用Bar()之后,循环体总是很快
  • 对我很重要
  • CheckSomething()价格昂贵,因此我不希望Foo()更频繁地被调用

是否有保证安全的方式来调用Foo()当且仅当它尚未执行并且在退出之前打电话给CheckSomething()

2 个答案:

答案 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)。

再次感谢您的帮助!