Last active
June 6, 2025 13:56
-
-
Save PlugFox/a923f32c9301a653116590da7cc18674 to your computer and use it in GitHub Desktop.
Mutex in Dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'dart:collection'; | |
/// A simple mutex implementation using a queue of completers. | |
/// This allows for synchronizing access to a critical section of code, | |
/// ensuring that only one task can execute the critical section at a time. | |
class Mutext { | |
/// Creates a new instance of the mutex. | |
Mutext(); | |
/// Queue of completers representing tasks waiting for the mutex. | |
final DoubleLinkedQueue<Completer<void>> _queue = DoubleLinkedQueue<Completer<void>>(); | |
/// Check if the mutex is currently locked. | |
bool get isLocked => _queue.isNotEmpty; | |
/// Returns the number of tasks waiting for the mutex. | |
int get tasks => _queue.length; | |
/// Locks the mutex and returns | |
/// a future that completes when the lock is acquired. | |
/// The returned function can be called to unlock the mutex, | |
/// but it should only be called once and relatively expensive to call. | |
Future<void> lock() { | |
final previous = _queue.lastOrNull?.future ?? Future<void>.value(); | |
_queue.add(Completer<void>.sync()); | |
return previous; | |
} | |
/// Unlocks the mutex, allowing the next waiting task to proceed. | |
void unlock() { | |
if (_queue.isEmpty) { | |
assert(false, 'Mutex unlock called when no tasks are waiting.'); | |
return; | |
} | |
final completer = _queue.removeFirst(); // Remove the current lock holder | |
if (completer.isCompleted) { | |
assert(false, 'Mutex unlock called when the completer is already completed.'); | |
return; | |
} | |
completer.complete(); | |
} | |
/// Synchronizes the execution of a function, ensuring that only one | |
/// task can execute the function at a time. | |
Future<T> synchronize<T>(Future<T> Function() action) async { | |
await lock(); | |
try { | |
return await action(); | |
} finally { | |
unlock(); | |
} | |
} | |
} | |
void main() async { | |
final mutext = Mutext(); | |
// Simulate a critical section | |
Future<void> criticalSection(int id) async { | |
print('Task $id is in the critical section'); | |
await Future<void>.delayed(const Duration(seconds: 1)); | |
print('Task $id is leaving the critical section'); | |
} | |
// Start multiple tasks | |
for (var i = 0; i < 5; i++) | |
mutext.synchronize(() => criticalSection(i)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment