EngineerSpock
EngineerSpock

Reputation: 2675

Updateable (resetable) timeout of Wait on a synchronization construction such as ManualResetEvent

Here is the description of the problem:

I need to make an API call synchronized. In order to make this call synchronized, I defined a ManualResetEvent and called WaitOne on it. WaitOne is called after the call to external COM object. In some circumstances it never returns. That's why I must define a timeout for that Wait call. But, I can't pass a constant into Wait method, because if the call was successfull than this API receives events from the COM object and in each handler of an event, timeout passed into WaitOne should be reset.

Consider the example:

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);
}

I'm just wondering whether anybody faced this problem or not. I'm sure this should be a common situation. As I understand there is no "out of the box" solution. So I have to build my own syncronization primitive, or maybe someone have already done it?

Update. I wanted something like this (implemented by myself):

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;
            }
        }
    }

Upvotes: 0

Views: 220

Answers (1)

RobH
RobH

Reputation: 3612

You could enter a loop and restart the wait:

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

Then set your event in the event handler.

private void SenderOnOnExchange () 
{
    operationInProcess.Set();
}

Upvotes: 1

Related Questions