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() func, {
Duration? timeout,
}) async {
final prev = last;
final completer = Completer<void>.sync();
last = completer.future;
try {
// If there is a previous running block, wait for it
if (prev != null) {
if (timeout != null) {
// This could throw a timeout error
await prev.timeout(timeout);
} else {
await prev;
}
}
// Run the function and return the result
var result = func();
if (result is Future) {
return await result;
} else {
return result;
}
} finally {
// Cleanup
// waiting for the previous task to be done in case of timeout
void complete() {
// Only mark it unlocked when the last one complete
if (identical(last, completer.future)) {
last = null;
}
completer.complete();
}
// In case of timeout, wait for the previous one to complete too
// before marking this task as complete
if (prev != null && timeout != null) {
// But we still returns immediately
// ignore: unawaited_futures
prev.then((_) {
complete();
});
} else {
complete();
}
}
}