Todd Menier
Todd Menier

Reputation: 39319

How do I check for and reset a timeout atomically?

I have a method that checks whether some timeout period has expired, and if it has, resets the start time and returns true:

bool CheckAndResetTimeout() {
    if (DateTime.UtcNow > _start + _timeout) {
        _start = DateTime.UtcNow;
        return true;
    }
    return false;
}

How can I make this thread safe in the sense that if 2 threads hit it at the same time, it is guaranteed to only return true once? I think this can be achieved via double-check locking, but I was hoping to find something in the BCLs (under System.Threading most likely) that might provide a higher-level abstraction for this.

Upvotes: 0

Views: 131

Answers (2)

Todd Menier
Todd Menier

Reputation: 39319

I hoped to avoid a lock if possible, such as by composing lighter-weight constructs from Sysetm.Threading.Interlocked, but I haven't come up with a good way to do that. So for now I'm doing double-checked locking, which at least avoids the lock overhead most of the time.

private readonly object _timeoutLock = new object();

public bool CheckAndResetTimeout() {
    if (DateTime.UtcNow > _start + _timeout) {
        lock (_timeoutLock) {
            if (DateTime.UtcNow > _start + _timeout) {
                _start = DateTime.UtcNow;
                return true;
            }
        }
    }
    return false;
}

Upvotes: 1

Jonathan Amend
Jonathan Amend

Reputation: 12815

You can use the lock keyword for this:

static object TimerLock = new object();
static bool CheckAndResetTimeout()
{
    lock (TimerLock)
    {
        if (DateTime.UtcNow > _start + _timeout)
        {
            _start = DateTime.UtcNow;
            return true;
        }
        return false;
    }
}

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

Upvotes: 3

Related Questions