这是否是实现等待条件超时的有效模式?目标是允许另一个线程在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
保证内容的信息:
https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
秒表课程有助于操纵与时间相关的操作 托管代码中的性能计数器。具体来说,频率 可以使用字段和GetTimestamp方法代替非托管方法 Win32 API QueryPerformanceFrequency和QueryPerformanceCounter。
这使我得出Stopwatch
使用Stopwatch
的结论
得到它的基础反击。
https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408.aspx
QPC多久翻身一次? 从最近的系统启动起不少于100年,并且基于所使用的底层硬件计时器可能更长。对于大多数应用程序,翻转不是一个问题。
所以是的,根本不是一个问题。
答案 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();
如果您想从其他线程取消它,可以将其设为静态。