synchronized<T> method
Runs computation once this lock is available, preventing any other
call to synchronized on this lock from running concurrently.
If timeout is specified, this waits at most that Duration to
acquire the lock; computation is never called and a TimeoutException
is thrown if the lock cannot be acquired in time. If timeout is
null (the default), this waits indefinitely.
Returns a Future that completes with the value returned by
computation (or its awaited result, if it returns a Future) once
computation finishes and the lock is released. Any error thrown by
computation is rethrown through the returned Future.
Implementation
@override
Future<T> synchronized<T>(
FutureOr<T> Function() computation, {
Duration? timeout,
}) async {
// [timeout] bounds the whole acquisition, not each lock in turn, so the
// budget is spent against a single stopwatch. Passing [timeout] down
// unchanged would let a caller wait up to `locks.length * timeout`.
final stopwatch = timeout == null ? null : (Stopwatch()..start());
Duration? remaining() {
if (timeout == null) {
return null;
}
final left = timeout - stopwatch!.elapsed;
// A non-positive budget must still time out rather than wait forever.
return left > Duration.zero ? left : Duration.zero;
}
FutureOr<T> runWithLocks(Iterator<Lock> iterator) {
if (!iterator.moveNext()) {
return computation();
} else {
final currentLock = iterator.current;
return currentLock.synchronized(
() => runWithLocks(iterator),
timeout: remaining(),
);
}
}
return runWithLocks(_locks.iterator);
}