Skip to content

Commit

Permalink
build: move synchronized to subdir and prevent github dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
alextekartik committed Jun 18, 2020
1 parent 2d876ae commit feb95bb
Show file tree
Hide file tree
Showing 38 changed files with 429 additions and 217 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
.packages
.pub/
build/
packages
# Remove the following pattern if you wish to check in your lock file
pubspec.lock

Expand All @@ -22,3 +21,5 @@ doc/api/
*.iml
*.ipr
*.iws
# VS code ide
.vscode/
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ language: dart
sudo: required
dist: trusty
dart:
- stable
- 2.6.0
- stable
- beta
- dev
before_script:
- pub run chrome_travis:init
- source $(pub run chrome_travis:env_rc)
script:
- dart tool/travis.dart
Expand Down
184 changes: 3 additions & 181 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,186 +4,8 @@

Basic lock mechanism to prevent concurrent access to asynchronous code

## Goal
## Documentation

You were missing hard to debug deadlocks, here it is!

The goal is to propose a solution similar to critical sections and offer a simple `synchronized` API à la Java style.
It provides a basic Lock/Mutex solution to allow features like transactions.

The name is biased as we are single threaded in Dart. However since we write asychronous code (await) like we would
write synchronous code, it makes the overall API feel the same.

The goal is to ensure for a single process (single isolate) that some asynchronous operations can run
without conflict. It won't solve cross-process (or cross-isolate) synchronization.

For single process (single isolate) accessing some resources (database..), it can help to
* Provide transaction on database system that don't have transaction mechanism (mongodb, file system)
* In html application make sure some asynchronous UI operation are not conflicting (login, transition)

## Feature

* By default a lock is not reentrant
* Timeout support
* Support for reentrant lock (using Zone)
* Consistent behavior (i.e. if it is unlocked calling synchronized grab the lock)
* Values and Errors are properly reported to the caller
* Work on Browser, DartVM and Flutter
* No dependencies (other than the sdk itself)

It differs from the `pool` package used with a resource count of 1 by supporting a reentrant option

## Usage

A simple usage example:

```dart
import 'package:synchronized/synchronized.dart';
main() async {
// Use this object to prevent concurrent access to data
var lock = new Lock();
...
await lock.synchronized(() async {
// Only this block can run (once) until done
...
});
}
```

If you need a re-entrant lock you can use

```dart
var lock = new Lock(reentrant: true);
// ...
await lock.synchronized(() async {
// do some stuff
// ...
await lock.synchronized(() async {
// other stuff
}
});
```
A basic lock is not reentrant by default and does not use Zone. It behaves like an async executor with a pool capacity
of 1

```dart
var lock = Lock();
// ...
lock.synchronized(() async {
// do some stuff
// ...
});
```

The return value is preserved

```dart
int value = await lock.synchronized(() {
return 1;
});
```

Using the `package:synchronized/extension.dart` import, you can turn any object into a lock. `synchronized()` can then be called on any
object

```dart
import 'package:synchronized/extension.dart';
class MyClass {
/// Perform a long action that won't be called more than one at a time.
Future performAction() {
// Lock at the instance level
return synchronized(() async {
// ...uninterrupted action
});
}
}
```

## How it works

The next tasks is executed once the previous one is done

Re-entrant locks uses `Zone` to know in which context a block is running in order to be reentrant. It maintains a list
of inner tasks to be awaited for.

## Example

Consider the following dummy code

```dart
Future writeSlow(int value) async {
await Future.delayed(new Duration(milliseconds: 1));
stdout.write(value);
}
Future write(List<int> values) async {
for (int value in values) {
await writeSlow(value);
}
}
Future write1234() async {
await write([1, 2, 3, 4]);
}
```

Doing

```dart
write1234();
write1234();
```
would print

11223344

while doing

```dart
lock.synchronized(write1234);
lock.synchronized(write1234);
```

would print

12341234

## The Lock instance

Have in mind that the `Lock` instance must be shared between calls in order to effectively prevent concurrent execution. For instance, in the example below the lock instance is the same between all `myMethod()` calls.

```dart
class MyClass {
final _lock = new Lock();
Future<void> myMethod() async {
await _lock.synchronized(() async {
step1();
step2();
step3();
});
}
}
```

Typically you would create a global or static instance Lock to prevent concurrent access to
a global resource or a class instance Lock to prevent concurrent modifications of
class instance data and resources.

## Features and bugs

Please feel free to:
* file feature requests and bugs at the [issue tracker][tracker]
* or [contact me][contact_me]
* [How to][how_to] guide


[tracker]: https://github.com/tekartik/synchronized.dart/issues
[contact_me]: http://contact.tekartik.com/
[how_to]: https://github.com/tekartik/synchronized.dart/blob/master/doc/how_to.md
* [Documentation](https://github.com/tekartik/synchronized.dart/blob/master/synchronized/README.md)
* [API reference](https://pub.dartlang.org/documentation/synchronized/latest/synchronized/synchronized-library.html)

21 changes: 8 additions & 13 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
name: synchronized
description: Lock mechanism to prevent concurrent access to asynchronous code.
version: 2.2.0
homepage: https://github.com/tekartik/synchronized.dart
name: synchronized_repo
description: Synchronized repo
version: 0.1.0
publish_to: none

environment:
sdk: '>=2.6.0 <3.0.0'
sdk: '>=2.8.0 <3.0.0'

dev_dependencies:
pedantic: '>=1.9.0 <3.0.0'
pub_semver:
test: '>=1.5.0'
process_run: '>=0.10.3'
chrome_travis:
git:
url: git://github.com/tekartik/chrome_travis.dart
ref: dart2
build_runner: '>=0.9.2'
build_test: '>=0.10.3'
build_web_compilers: '>=1.1.0'
process_run:
io:
yaml:
version: '>=0.2.2'


24 changes: 24 additions & 0 deletions synchronized/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Files and directories created by pub
.dart_tool/
.packages
.pub/
build/
packages
# Remove the following pattern if you wish to check in your lock file
pubspec.lock

# Files created by dart2js
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json

# Directory created by dartdoc
doc/api/

# JetBrains IDEs
.idea/
*.iml
*.ipr
*.iws
File renamed without changes.
24 changes: 24 additions & 0 deletions synchronized/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Copyright (c) 2016, Alexandre Roux Tekartik.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Tekartik nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Loading

0 comments on commit feb95bb

Please sign in to comment.