0

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

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()在退出之前调用时,是否有一种保证安全的调用方式?

4

2 回答 2

3

Foo如果我理解正确,如果它已经被执行,你想阻止它运行。似乎您可以为此使用监视器

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.Exitin放在finally子句中的人,请参阅 Eric Lippert 的Locks and exceptions do not mix。)

这不会阻止Foo被调用,但会阻止多个线程处于循环中,因此CheckSomething不能从Foo.

您的要求有点模糊,所以这可能不会完全符合您的要求。如果一个线程已经调用CheckSomethingfalse返回但尚未退出,并且另一个线程进入该方法,那么您想要发生的事情会有些模糊。处理这种竞争条件会有点棘手。

于 2013-09-09T20:42:25.480 回答
1

借助 Servy 的评论,我现在设法通过对共享内存进行版本控制来解决问题:

  • 每次调用都会Bar增加底层共享内存的版本
  • Bar返回我传递给的新的当前版本Foo
  • Foo将当前版本传递给CheckSomething-wrapper
  • CheckSomething-wrapper 如果给定版本小于共享内存的当前版本,则立即返回 false ->Foo退出

Bar唯一的问题是在短时间内调用太多会导致该Foo方法饿死,这就是为什么如果版本差异大于一个恒定值(例如 50),我仍然运行它的原因。

再次感谢您的帮助!

于 2013-09-09T21:18:43.853 回答