在具有追溯可配置超时的监视器上等待?

时间:2016-02-03 13:29:26

标签: c# .net stopwatch

这是否是实现等待条件超时的有效模式?目标是允许另一个线程在SomeMethod被调用后设置超时。

readonly object someLock = new object();
int timeout;
bool timeoutEnabled;
bool someCondition;

void SomeMethod()
{
    lock (someLock)
    {
        Stopwatch sw = Stopwatch.StartNew();
        while (!SomeCondition)
        {
            if (!timeoutEnabled)
                Monitor.Wait(someLock);
            else
            {
                long timeToWait = timeout - sw.ElapsedMilliseconds;
                if (timeToWait > 0)
                    Monitor.Wait(someLock, (int)timeToWait);
                else
                    break;
            }
        }
        // Do things.
    }
}

void DisableTimeout()
{
    lock (someLock)
    {
        timeoutEnabled = false;
        Monitor.PulseAll(someLock);
    }
}

void SetTimeout(int newTimeout)
{
    lock (someLock)
    {
        timeout = newTimeout;
        timeoutEnabled = true;
        Monitor.PulseAll(someLock);
    }
}

我看到的问题是我没有停止Stopwatch。我假设它有足够的范围,不会溢出任何合理的程序执行时间。否则,该方法可能会等待超过给定的时间限制,在等待时抛出ArgumentOutOfRange异常或做其他坏事。

Stopwatch的{​​{1}}属性类型为ElapsedMilliseconds。但是,基础计数器在没有包装的情况下实际上无法工作将近3亿年。

有没有办法找出实际的限制是什么?或者是否保证long可以使用的最短时间段?我应该预计它会是几分钟,几小时,几天或几年吗?

更新

我终于能够找到更多关于Stopwatch保证内容的信息:

2 个答案:

答案 0 :(得分:2)

如果您引入新的ManualResetEvent,则可以执行WaitHandle.WaitAll()。这将要求您使用WaitHandles而不是Monitor。

在这种情况下,您可以区分您最初等待的事件和事件'嘿,您需要重新考虑超时'。

答案 1 :(得分:0)

背景工作者怎么样?为此,您可以启用取消支付

public BackgroundWorker myWorker = new BackgroundWorker();
myWoker.WorkerSupportsCancellation = true;
myWorker.DoWork += new DoWorkEventHandler(waitingMethod);
myWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(finalChekc);

此处将在不同的线程中运行的函数

private void waitingMethod(object sender, DoWorkEventArgs e)
{
    bool endConditions = false;
    BackgroundWorker worker = sender as BackgroundWorker;
    while (!endConditions && !worker.CancellationPending)
    {
        endConditions = checkEndConditions();
        if(worker.CancellationPending)
        {
            endConditions = true;
            e.Cancel = true;
        }
        thread.Sleep(20);
    }
}

有线程结束时调用的函数。您可以检查它是否已完成,因为它已自然完成,或有人取消了它。

void deviceSearchCompleted(object sender, RunWorkerCompletedEventArgs e)
{
     if(e.Cancelled)  blablabla
}

然后,您可以从任何地方调用BackgroundWorker并取消它

myWorker.CancelAsync();

如果您想从其他线程取消它,可以将其设为静态。