我正在尝试实现以下功能:
class WeightResolver {
WeightMonitor _source;
bool _cancelled;
Weight _threshold;
public Cancel() {
_cancelled = true;
}
public Weight Resolve(){
_cancelled = false;
while(_source.CurrentWeight < threshold ) {
if(_cancelled)
throw new CancelledOperationException();
// Wait until one of the above conditions is met
}
return _source.CurrentWeight
}
}
但是我遇到了管理我的线程的麻烦。例如,Cancel方法通过事件注册,Resolve调用如下:
_activity_timeout_manager.TimeoutHandler += new Action(_weight_resolver.Cancel())l
try {
var weight = _weight_resolver.Resolve();
}
catch(CancelledOperationException) { .... }
其中活动管理器正在运行一个计时器,它使用TimeoutHandler.Invoke()调用事件;
问题在于即使它已正确注册事件,也永远不会调用Cancel()。我相信这是因为它正在调用的线程正在旋转,因此它永远不会有机会在CPU上运行。
如果不调用Resolve()异步,我该怎么做才能解决这个问题? WeightResolver.Resolve()非常适合保持同步,因为调用它的代码应该旋转,除非提供一些返回。
编辑:澄清我要求的内容。这似乎是一个相当常见的设置,如果没有一种简单的标准方法来处理它,我会感到惊讶。我以前从来没有碰过这种情况,也不知道究竟是什么。
答案 0 :(得分:1)
这可能不适合您,但根据您提供的信息,我建议查看thread.Join(XXX),其中XXX是等待的毫秒数。它将大大简化您的代码。
http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx
你可以将调用线程阻塞到新线程一段指定的时间,之后你可以中止Resolve线程。
resolveThread.Start();
resolveThread.Join(2000); //this will block the main thread, thus making resolve synchronous
resolveThread.Abort(); //timeout has expired
答案 1 :(得分:0)
这个while循环是否会放弃CPU?
while(_source.CurrentWeight < threshold )
如果没有,那么您的不活动计时器将无法运行。您可能希望使用ManualResetEvents(而不是循环...有任何设置_source.CurrentWeight设置事件)或每隔一段时间抛出一个Thread.yield()。
答案 2 :(得分:0)
这里需要的是条件变量。我不是专门知道.NET,但一般来说你会有类似的东西
Condition cond;
Mutex lock;
public Cancel() {
lock.lock()
_cancelled = true;
cond.signal(lock);
lock.unlock();
}
public Weight Resolve(){
_cancelled = false;
lock.lock();
while(_source.CurrentWeight < threshold) {
if(_cancelled)
{
lock.unlock();
throw new CancelledOperationException();
}
cond.timedWait(lock, 100);
// Wait until one of the above conditions is met
}
lock.unlock();
return _source.CurrentWeight
}
如果你的WeightResolver在重量变化时以相同的条件发出信号,那就更好了。 e.g。
Condition cond;
Mutex lock;
public Cancel() {
lock.lock()
_cancelled = true;
cond.signal(lock);
lock.unlock();
}
public Weight Resolve(){
_cancelled = false;
lock.lock();
while(_source.CurrentWeight < threshold) {
if(_cancelled)
{
lock.unlock();
throw new CancelledOperationException();
}
cond.wait(lock);
// Wait until one of the above conditions is met
}
lock.unlock();
return _source.CurrentWeight
}
在WeightMonitor Class中你有这样的东西。
public void updateWeight()
{
lock.lock();
...update weight;
cond.signal(lock);
lock.unlock();
}
其中Conditionvariable和lock是相同的。两个班级。
这是条件变量的标准用法,这也是通常实现连接的方式。
答案 3 :(得分:0)
您应该使用ManualResetEvent
代替bool
来取消。
class WeightResolver {
WeightMonitor _source;
ManualResetEvent _cancelled = new ManualResetEvent(false);
Weight _threshold;
public Cancel() {
_cancelled.Set();
}
public Weight Resolve(){
_cancelled = false;
while(_source.CurrentWeight < threshold ) {
if(_cancelled.WaitOne(100))
throw new CancelledOperationException();
// Wait until one of the above conditions is met
}
return _source.CurrentWeight
}
}