@@ -126,6 +126,7 @@ class SerializedMutex {
126126/// Uses a [SendPort] to communicate with the source mutex.
127127class SharedMutex implements Mutex {
128128 final ChildPortClient client;
129+ bool closed = false ;
129130
130131 SharedMutex ._(this .client);
131132
@@ -135,6 +136,9 @@ class SharedMutex implements Mutex {
135136 throw LockError ('Recursive lock is not allowed' );
136137 }
137138 return runZoned (() async {
139+ if (closed) {
140+ throw const ClosedException ();
141+ }
138142 await _acquire (timeout: timeout);
139143 try {
140144 final T result = await callback ();
@@ -174,7 +178,20 @@ class SharedMutex implements Mutex {
174178 }
175179
176180 @override
181+
182+ /// Wait for existing locks to be released, then close this SharedMutex
183+ /// and prevent further locks from being taken out.
177184 Future <void > close () async {
185+ if (closed) {
186+ return ;
187+ }
188+ closed = true ;
189+ // Wait for any existing locks to complete, then prevent any further locks from being taken out.
190+ await _acquire ();
191+ client.fire (const _CloseMessage ());
192+ // Close client immediately after _unlock(),
193+ // so that we're sure no further locks are acquired.
194+ // This also cancels any lock request in process.
178195 client.close ();
179196 }
180197}
@@ -184,6 +201,7 @@ class _SharedMutexServer {
184201 Completer ? unlock;
185202 late final SerializedMutex serialized;
186203 final Mutex mutex;
204+ bool closed = false ;
187205
188206 late final PortServer server;
189207
@@ -198,6 +216,11 @@ class _SharedMutexServer {
198216 if (arg is _AcquireMessage ) {
199217 var lock = Completer .sync ();
200218 mutex.lock (() async {
219+ if (closed) {
220+ // The client will error already - we just need to ensure
221+ // we don't take out another lock.
222+ return ;
223+ }
201224 assert (unlock == null );
202225 unlock = Completer .sync ();
203226 lock.complete ();
@@ -208,6 +231,10 @@ class _SharedMutexServer {
208231 } else if (arg is _UnlockMessage ) {
209232 assert (unlock != null );
210233 unlock! .complete ();
234+ } else if (arg is _CloseMessage ) {
235+ // Unlock and close (from client side)
236+ closed = true ;
237+ unlock? .complete ();
211238 }
212239 }
213240
@@ -224,6 +251,11 @@ class _UnlockMessage {
224251 const _UnlockMessage ();
225252}
226253
254+ /// Unlock and close
255+ class _CloseMessage {
256+ const _CloseMessage ();
257+ }
258+
227259class LockError extends Error {
228260 final String message;
229261
0 commit comments