semaphore
Version: 1.0.1
Lightweight implementation of a semaphore, a condition variable, and a lock that can be used to control (synchronize) access to a shared resources within an isolate.
Examples
Semaphore example:
import 'dart:async';
import 'package:semaphore/semaphore.dart';
Future<void> main(List<String> args) async {
const maxCount = 3;
final running = <int>[];
var simultaneous = 0;
final sm = LocalSemaphore(maxCount);
final tasks = <Future<void>>[];
for (var i = 0; i < 9; i++) {
tasks.add(Future(() async {
try {
await sm.acquire();
running.add(i);
if (simultaneous < running.length) {
simultaneous = running.length;
}
print('Start $i, running $running');
await _doWork(100);
running.remove(i);
print('End $i, running $running');
} finally {
sm.release();
}
}));
}
await Future.wait(tasks);
print('Max permits: $maxCount, max of simultaneously running: $simultaneous');
}
Future<void> _doWork(int ms) {
// Simulate work
return Future.delayed(Duration(milliseconds: ms));
}
Output:
Start 0, running [0]
Start 1, running [0, 1]
Start 2, running [0, 1, 2]
End 0, running [1, 2]
Start 3, running [1, 2, 3]
End 1, running [2, 3]
Start 4, running [2, 3, 4]
End 2, running [3, 4]
Start 5, running [3, 4, 5]
End 3, running [4, 5]
Start 6, running [4, 5, 6]
End 4, running [5, 6]
Start 7, running [5, 6, 7]
End 5, running [6, 7]
Start 8, running [6, 7, 8]
End 6, running [7, 8]
End 7, running [8]
End 8, running []
Max permits: 3, max of simultaneously running: 3
Conditional variables example:
import 'dart:async';
import 'dart:collection';
import 'dart:math';
import 'package:semaphore/condition_variable.dart';
import 'package:semaphore/lock.dart';
Future<void> main() async {
_sw.start();
await Future.wait([
_producer('1'),
_producer('2'),
_consumer('1'),
_consumer('2'),
_consumer('3'),
]);
}
var _bufferSize = 2;
var _itemId = 0;
final _items = Queue<int>();
final _lock = Lock();
final _notEmpty = ConditionVariable(_lock);
final _notFull = ConditionVariable(_lock);
final _sw = Stopwatch();
Future<void> _consumer(String id) async {
while (true) {
late int item;
await lock(_lock, () async {
while (_items.isEmpty) {
_print('Consumer ($id) is waiting for the item');
await _notEmpty.wait();
}
item = _items.removeFirst();
_print('Consumer ($id) receives an item ($item)');
await _notFull.signal();
});
_print('Consumer ($id) start consuming an item ($item)');
await _doWork(3000);
_print('Consumer ($id) finished consuming an item ($item)');
}
}
Future<void> _doWork(int max) async {
final milliseconds = Random().nextInt(max);
await Future<void>.delayed(Duration(milliseconds: milliseconds));
}
void _print(String message) {
final elapsed = _sw.elapsedMilliseconds / 1000;
print('$message, items ($_items) [$elapsed]');
}
Future<void> _producer(String id) async {
while (true) {
_print('Producer ($id) begin producing the item');
await _doWork(1000);
_print('Producer ($id) finished producing the item');
await lock(_lock, () async {
while (_items.length == _bufferSize) {
_print('Producer ($id) is waiting for free slot');
await _notFull.wait();
}
final item = _itemId++;
_items.add(item);
_print('Producer ($id) sent the item ($item)');
await _notEmpty.signal();
});
}
}
Output:
Producer (1) begin producing the item, items ({}) [0.001]
Producer (2) begin producing the item, items ({}) [0.022]
Consumer (1) is waiting for the item, items ({}) [0.038]
Consumer (2) is waiting for the item, items ({}) [0.039]
Consumer (3) is waiting for the item, items ({}) [0.039]
Producer (2) finished producing the item, items ({}) [0.406]
Producer (2) sent the item (0), items ({0}) [0.408]
Producer (2) begin producing the item, items ({0}) [0.41]
Consumer (1) receives an item (0), items ({}) [0.41]
Consumer (1) start consuming an item (0), items ({}) [0.411]
Producer (2) finished producing the item, items ({}) [0.42]
Producer (2) sent the item (1), items ({1}) [0.42]
Producer (2) begin producing the item, items ({1}) [0.42]
Consumer (2) receives an item (1), items ({}) [0.42]
Consumer (2) start consuming an item (1), items ({}) [0.421]
Producer (1) finished producing the item, items ({}) [0.443]
Producer (1) sent the item (2), items ({2}) [0.444]
Producer (1) begin producing the item, items ({2}) [0.444]
Consumer (3) receives an item (2), items ({}) [0.444]
Consumer (3) start consuming an item (2), items ({}) [0.444]
Producer (1) finished producing the item, items ({}) [0.566]
Producer (1) sent the item (3), items ({3}) [0.566]
Producer (1) begin producing the item, items ({3}) [0.566]
Producer (2) finished producing the item, items ({3}) [0.596]
Producer (2) sent the item (4), items ({3, 4}) [0.596]
Producer (2) begin producing the item, items ({3, 4}) [0.596]
Consumer (3) finished consuming an item (2), items ({3, 4}) [0.72]
Consumer (3) receives an item (3), items ({4}) [0.72]
Consumer (3) start consuming an item (3), items ({4}) [0.72]
Producer (2) finished producing the item, items ({4}) [0.733]
Producer (2) sent the item (5), items ({4, 5}) [0.734]
Producer (2) begin producing the item, items ({4, 5}) [0.734]
Producer (2) finished producing the item, items ({4, 5}) [1.346]
Producer (2) is waiting for free slot, items ({4, 5}) [1.347]
Producer (1) finished producing the item, items ({4, 5}) [1.55]
Producer (1) is waiting for free slot, items ({4, 5}) [1.551]
Consumer (2) finished consuming an item (1), items ({4, 5}) [2.561]
Consumer (2) receives an item (4), items ({5}) [2.562]
Consumer (2) start consuming an item (4), items ({5}) [2.562]
Producer (2) sent the item (6), items ({5, 6}) [2.562]
Producer (2) begin producing the item, items ({5, 6}) [2.562]
Producer (2) finished producing the item, items ({5, 6}) [3.3]
Producer (2) is waiting for free slot, items ({5, 6}) [3.3]
Consumer (1) finished consuming an item (0), items ({5, 6}) [3.337]
Consumer (1) receives an item (5), items ({6}) [3.337]
Consumer (1) start consuming an item (5), items ({6}) [3.337]
Producer (1) sent the item (7), items ({6, 7}) [3.338]
Producer (1) begin producing the item, items ({6, 7}) [3.338]
Consumer (3) finished consuming an item (3), items ({6, 7}) [3.575]
Consumer (3) receives an item (6), items ({7}) [3.575]
Consumer (3) start consuming an item (6), items ({7}) [3.575]
Producer (2) sent the item (8), items ({7, 8}) [3.576]
Producer (2) begin producing the item, items ({7, 8}) [3.576]