0

这是问题的描述:

我需要同步 API 调用。为了使这个调用同步,我定义了一个 ManualResetEvent 并在它上面调用了 WaitOne。在调用外部 COM 对象之后调用 WaitOne。在某些情况下,它永远不会返回。这就是为什么我必须为那个 Wait 调用定义一个超时。但是,我不能将常量传递给 Wait 方法,因为如果调用成功,则此 API 从 COM 对象接收事件并且在事件的每个处理程序中,传递给 WaitOne 的超时应该被重置。

考虑这个例子:

private ManualResetEvent operationIsInProcess;
private static readonly IComObject sender;
private int timeout = 30000;

public void Start() {                           
    sender.OnExchange += SenderOnOnExchange;            
}
private void StartOperation(){
    sender.StartAsyncExchange();
    operationIsInProcess.WaitOne(timeout);
}

private void SenderOnOnExchange(){
    //somehow we need to reset or update that timeout on WaitOne
    //operationInProcess.Update(timeout);
}

我只是想知道是否有人遇到过这个问题。我相信这应该是一种常见的情况。据我了解,没有“开箱即用”的解决方案。所以我必须建立自己的同步原语,或者也许有人已经做到了?

更新。 我想要这样的东西(由我自己实现):

public class UpdateableSpin {
        private readonly object lockObj = new object();
        private bool shouldWait;
        private long taskExecutionStartingTime;

        public UpdateableSpin(bool initialState) {
            shouldWait = initialState;
        }

        public void Wait(TimeSpan executionTimeout, int spinDuration = 0) {
            UpdateTimeout();
            while (shouldWait && DateTime.UtcNow.Ticks - taskExecutionStartingTime < executionTimeout.Ticks) {
                lock (lockObj) {
                    Thread.Sleep(spinDuration);
                }
            }
        }

        public void UpdateTimeout() {
            lock (lockObj) {
                taskExecutionStartingTime = DateTime.UtcNow.Ticks;
            }
        }

        public void Reset() {
            lock (lockObj) {
                shouldWait = true;
            }
        }

        public void Set() {
            lock (lockObj) {
                shouldWait = false;
            }
        }
    }
4

1 回答 1

1

您可以进入一个循环并重新开始等待:

while (true)
{
    if (!operationIsInProcess.WaitOne(timeout))
    {
        // timed out 
        break;
    }
    else
    {
        // Reset the signal.
        operationIsInProcess.Reset();
    }
}

然后在事件处理程序中设置您的事件。

private void SenderOnOnExchange () 
{
    operationInProcess.Set();
}
于 2015-01-19T11:57:10.043 回答