synchronized 1.4.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 94

synchronized

Build Status

Basic lock mechanism to prevent concurrent access to asynchronous code

Goal

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 (mongodbn, file system)
  • In html application make sure some asynchronous UI operation are not conflicting (login, transition)

Feature

  • Synchronized block are reentrant
  • Timeout support
  • Support for non-reentrant lock (not 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 and DartVM
  • No dependencies (other than the sdk itself)

It differs from the pool package used with a resource count of 1 by being reentrant

Usage

A simple usage example:

import 'package:synchronized/synchronized.dart';

main() {
  var lock = new Object();
  synchronized(lock, () async {
    // Only this block can run (once) until done 
    ...
  });
}

Any object can become a locker, so in a class method you can use

synchronized(this, () async {
  // do some stuff
});

A SynchronizedLock object has a locked helper method, it is reentrant and uses Zone

var lock = new SynchronizedLock();
lock.synchronized(() async {
  // do some 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

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

The return value is preserved

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

How it works

SynchronizedLock uses Zone to know in which context a block is running in order to be reentrant. Locks maintain a list of active locks and tasks to run them consecutively

Example

Consider the following dummy code

Future writeSlow(int value) async {
  new 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

write1234();
write1234();

would print

11223344

while doing

lock.synchronized(write1234);
lock.synchronized(write1234);

would print

12341234

Features and bugs

Please feel free to:

Changelog

1.4.0

  • Re-use non-reentrant lock in synchronized method

1.3.0

  • Add non-reentrant lock that do not use Zone

1.2.1

  • implicit-casts: false (testing dart2 support)

1.2.0

  • Use generic instead of 2.0 deprecated comments

1.1.0

  • Fix inner task issue, next outer task will wait for all inner tasks to terminate
  • Properly handle nested thrown error

1.0.0

  • Bump to version 1.0.0

0.1.0

  • Initial version

example/synchronized_example.dart

import 'dart:async';
import 'dart:io';
import 'package:synchronized/synchronized.dart';

Future writeSlow(int value) async {
  new 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]);
}

class Demo {
  Future test1() async {
    stdout.writeln("not synchronized");
    //await Future.wait([write1234(), write1234()]);
    write1234();
    write1234();

    await new Future.delayed(new Duration(milliseconds: 50));
    stdout.writeln();
  }

  Future test2() async {
    stdout.writeln("synchronized");

    synchronized(this, write1234);
    synchronized(this, write1234);

    await new Future.delayed(new Duration(milliseconds: 50));

    stdout.writeln();
  }

  Future readme1() async {
    synchronized(this, () async {
      // do some stuff
    });
  }

  Future readme2() async {
    var lock = new SynchronizedLock();
    if (!lock.locked) {
      lock.synchronized(() async {
        // do some stuff
      });
    }
  }

  Future readme3() async {
    int value = await synchronized(this, () {
      return 1;
    });
    stdout.writeln("got value: ${value}");
  }
}

main() async {
  var demo = new Demo();

  await demo.test1();
  await demo.test2();
  await demo.readme1();
  await demo.readme1();
  await demo.readme3();
}

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  synchronized: "^1.4.0"

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:synchronized/synchronized.dart';
        
Version Uploaded Documentation Archive
1.4.0 Apr 5, 2018 Go to the documentation of synchronized 1.4.0 Download synchronized 1.4.0 archive
1.3.0 Mar 4, 2018 Go to the documentation of synchronized 1.3.0 Download synchronized 1.3.0 archive
1.2.1 Mar 1, 2018 Go to the documentation of synchronized 1.2.1 Download synchronized 1.2.1 archive
1.2.0 Jan 26, 2018 Go to the documentation of synchronized 1.2.0 Download synchronized 1.2.0 archive
1.1.0 Oct 15, 2017 Go to the documentation of synchronized 1.1.0 Download synchronized 1.1.0 archive
1.0.2 Oct 15, 2017 Go to the documentation of synchronized 1.0.2 Download synchronized 1.0.2 archive
1.0.1 Oct 15, 2017 Go to the documentation of synchronized 1.0.1 Download synchronized 1.0.1 archive
1.0.0 Feb 12, 2017 Go to the documentation of synchronized 1.0.0 Download synchronized 1.0.0 archive
0.1.0 Oct 14, 2016 Go to the documentation of synchronized 0.1.0 Download synchronized 0.1.0 archive

Analysis

We analyzed this package on Apr 23, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.49.0
  • pana: 0.10.6

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
89 / 100
Health:
Code health derived from static analysis. [more]
100 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100 / 100
Overall score:
Weighted score of the above. [more]
94
Learn more about scoring.

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:synchronized/synchronized.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.24.0 <2.0.0
Dev dependencies
browser any
chrome_travis
dev_test >=0.9.3
test >=0.12.0