1+ ** [ Requirements] ( #requirements ) ** |
2+ ** [ Installation] ( #installation ) ** |
3+ ** [ Usage] ( #usage ) ** |
4+ ** [ License and authors] ( #license-and-authors ) ** |
5+ ** [ Donations] ( #donations ) **
6+
7+ # php-lock/lock
8+
9+ [ ![ Latest Stable Version] ( https://poser.pugx.org/malkusch/lock/version )] ( https://packagist.org/packages/malkusch/lock )
10+ [ ![ Total Downloads] ( https://poser.pugx.org/malkusch/lock/downloads )] ( https://packagist.org/packages/malkusch/lock )
11+ [ ![ Latest Unstable Version] ( https://poser.pugx.org/malkusch/lock/v/unstable )] ( //packagist.org/packages/malkusch/lock )
112[ ![ Build Status] ( https://travis-ci.org/php-lock/lock.svg?branch=master )] ( https://travis-ci.org/php-lock/lock )
13+ [ ![ License] ( https://poser.pugx.org/malkusch/lock/license )] ( https://packagist.org/packages/malkusch/lock )
214
315This library helps executing critical code in concurrent situations.
416
5- # Installation
17+ php-lock/lock follows semantic versioning. Read more on [ semver.org] [ 1 ] .
18+
19+ ----
20+
21+ ## Requirements
22+
23+ - PHP 7.1 or above
24+ - Optionally [ nrk/predis] [ 2 ] to use the predis locks.
25+ - Optionally the [ php-pcntl] [ 3 ] extension to enable locking with flock without
26+ busy waiting in CLI scripts.
627
7- Use [ Composer] ( https://getcomposer.org/ ) :
28+ ----
29+
30+ ## Installation
31+
32+ ### Composer
33+
34+ To use this library through [ composer] [ 4 ] , run the following terminal command
35+ inside your repository's root folder.
836
937``` sh
10- composer require malkusch/lock
38+ composer require " malkusch/lock"
1139```
1240
13- # Usage
41+ As an alternative, you can directly add this library to your ` composer.json ` .
1442
15- The package is in the namespace
16- [ ` malkusch\lock ` ] ( http://malkusch.github.io/lock/api/namespace-malkusch.lock.html ) .
43+ ``` json
44+ {
45+ "require" : {
46+ "malkusch/lock" : " ^1.4"
47+ }
48+ }
49+ ```
1750
18- ## Mutex
51+ To use the newest (maybe unstable) version, use ` dev-master ` as the version in
52+ your ` composer.json ` .
1953
20- The
21- [ ` Mutex ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.Mutex.html )
22- provides the API for this library.
54+ ``` json
55+ {
56+ "require" : {
57+ "malkusch/lock" : " dev-master"
58+ }
59+ }
60+ ```
61+
62+ ## Usage
63+
64+ This library uses the namespace ` malkusch\lock ` .
65+
66+ ### Mutex
2367
24- ### Mutex::synchronized()
68+ The [ ` malkusch\lock\mutex\Mutex ` ] [ 5 ] class is an abstract class and provides the
69+ base API for this library.
2570
26- [ ` Mutex::synchronized() ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.Mutex.html#_synchronized )
27- executes code exclusively. This method guarantees that the code is only executed
28- by one process at once. Other processes have to wait until the mutex is available.
29- The critical code may throw an exception, which would release the lock as well.
71+ #### Mutex::synchronized()
72+
73+ [ ` malkusch\lock\mutex\Mutex::synchronized() ` ] [ 6 ] executes code exclusively. This
74+ method guarantees that the code is only executed by one process at once. Other
75+ processes have to wait until the mutex is available. The critical code may throw
76+ an exception, which would release the lock as well.
77+
78+ This method returns what ever is returned to the given callable. The return
79+ value is not checked, thus it is up to the user to decide if for example the
80+ return value ` false ` or ` null ` should be seen as a failed action.
3081
3182Example:
83+
3284``` php
33- $mutex->synchronized(function () use ($bankAccount, $amount) {
85+ $newBalance = $ mutex->synchronized(function () use ($bankAccount, $amount) {
3486 $balance = $bankAccount->getBalance();
3587 $balance -= $amount;
3688 if ($balance < 0) {
37- throw new \DomainException("You have no credit.");
38-
89+ throw new \DomainException('You have no credit.');
3990 }
4091 $bankAccount->setBalance($balance);
92+
93+ return $balance;
4194});
4295```
4396
44- ### Mutex::check()
97+ #### Mutex::check()
98+
99+ [ ` malkusch\lock\mutex\Mutex::check() ` ] [ 7 ] sets a callable, which will be
100+ executed when [ ` malkusch\lock\util\DoubleCheckedLocking::then() ` ] [ 8 ] is called,
101+ and performs a double-checked locking pattern, where it's return value decides
102+ if the lock needs to be acquired and the synchronized code to be executed.
103+
104+ See [ https://en.wikipedia.org/wiki/Double-checked_locking ] [ 9 ] for a more
105+ detailed explanation of that feature.
45106
46- [ ` Mutex::check() ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.Mutex.html#_check )
47- performs a double-checked locking pattern. I.e. if the check fails, no lock
48- will be acquired. Else if the check was true, a lock will be acquired and the
49- check will be perfomed as well together with the critical code.
107+ If the check's callable returns ` false ` , no lock will be acquired and the
108+ synchronized code will not be executed. In this case the
109+ [ ` malkusch\lock\util\DoubleCheckedLocking::then() ` ] [ 8 ] method, will also return
110+ ` false ` to indicate that the check did not pass either before or after acquiring
111+ the lock.
112+
113+ In the case where the check's callable returns a value other than ` false ` , the
114+ [ ` malkusch\lock\util\DoubleCheckedLocking::then() ` ] [ 8 ] method, will
115+ try to acquire the lock and on success will perform the check again. Only when
116+ the check returns something other than ` false ` a second time, the synchronized
117+ code callable, which has been passed to ` then() ` will be executed. In this case
118+ the return value of ` then() ` will be what ever the given callable returns and
119+ thus up to the user to return ` false ` or ` null ` to indicate a failed action as
120+ this return value will not be checked by the library.
50121
51122Example:
123+
52124``` php
53- $mutex->check(function () use ($bankAccount, $amount) {
125+ $newBalance = $ mutex->check(function () use ($bankAccount, $amount) {
54126 return $bankAccount->getBalance() >= $amount;
55-
56127})->then(function () use ($bankAccount, $amount) {
57128 $balance = $bankAccount->getBalance();
58129 $balance -= $amount;
59130 $bankAccount->setBalance($balance);
131+
132+ return $balance;
60133});
134+
135+ if (false === $newBalance) {
136+ if ($balance < 0) {
137+ throw new \DomainException('You have no credit.');
138+ }
139+ }
61140```
62141
63142### Implementations
64143
65- The ` Mutex ` is an abstract class. You will have to choose an implementation:
144+ Because the [ ` malkusch\lock\mutex\Mutex ` ] ( #mutex ) class is an abstract class,
145+ you can choose from one of the provided implementations or create/extend your
146+ own implementation.
66147
67148- [ ` CASMutex ` ] ( #casmutex )
68149- [ ` FlockMutex ` ] ( #flockmutex )
@@ -74,19 +155,18 @@ The `Mutex` is an abstract class. You will have to choose an implementation:
74155- [ ` MySQLMutex ` ] ( #mysqlmutex )
75156- [ ` PgAdvisoryLockMutex ` ] ( #pgadvisorylockmutex )
76157
77-
78158#### CASMutex
79159
80- The ** CASMutex**
81- has to be used with a [ Compare-and-swap] ( https://en.wikipedia.org/wiki/Compare-and-swap ) operation.
82- This mutex is lock free. It will repeat executing the code until the CAS operation was
83- successful. The code should therefore notify the mutex by calling
84- [ ` CASMutex::notify() ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.CASMutex.html#_notify ) .
160+ The ** CASMutex** has to be used with a [ Compare-and-swap] [ 10 ] operation. This
161+ mutex is lock free. It will repeat executing the code until the CAS operation
162+ was successful. The code should therefore notify the mutex by calling
163+ [ ` malkusch\lock\mutex\CASMutex::notify() ` ] [ 11 ] .
85164
86- As the mutex keeps executing the critical code, it must not have any side effects
87- as long as the CAS operation was not successful.
165+ As the mutex keeps executing the critical code, it must not have any side
166+ effects as long as the CAS operation was not successful.
88167
89168Example:
169+
90170``` php
91171$mutex = new CASMutex();
92172$mutex->synchronized(function () use ($memcached, $mutex, $amount) {
@@ -118,8 +198,8 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
118198});
119199```
120200
121- Timeouts are supported as an optional second argument. This uses the pcntl extension if
122- possible or busy waiting if not.
201+ Timeouts are supported as an optional second argument. This uses the pcntl
202+ extension if possible or busy waiting if not.
123203
124204#### MemcachedMutex
125205
@@ -240,7 +320,6 @@ $mutex->synchronized(function () use ($pdo, $accountId, $amount) {
240320});
241321```
242322
243-
244323#### MySQLMutex
245324
246325The ** MySQLMutex** uses MySQL's
@@ -267,6 +346,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
267346 $bankAccount->setBalance($balance);
268347});
269348```
349+
270350#### PgAdvisoryLockMutex
271351
272352The ** PgAdvisoryLockMutex** uses PostgreSQL's
@@ -293,9 +373,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
293373});
294374```
295375
296-
297-
298- # License and authors
376+ ## License and authors
299377
300378This project is free and under the WTFPL.
301379Responsible for this project is Willem Stuursma-Ruwen
< [email protected] > .
@@ -305,4 +383,14 @@ Responsible for this project is Willem Stuursma-Ruwen <
[email protected] >.
305383If you like this project and feel generous donate a few Bitcoins here:
306384[ 1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA] ( bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA )
307385
308-
386+ [ 1 ] : http://semver.org
387+ [ 2 ] : https://github.com/nrk/predis
388+ [ 3 ] : http://php.net/manual/en/book.pcntl.php
389+ [ 4 ] : https://getcomposer.org
390+ [ 5 ] : https://github.com/php-lock/lock/blob/master/classes/mutex/Mutex.php
391+ [ 6 ] : https://github.com/php-lock/lock/blob/master/classes/mutex/Mutex.php#L38
392+ [ 7 ] : https://github.com/php-lock/lock/blob/master/classes/mutex/Mutex.php#L57
393+ [ 8 ] : https://github.com/php-lock/lock/blob/master/classes/util/DoubleCheckedLocking.php#L72
394+ [ 9 ] : https://en.wikipedia.org/wiki/Double-checked_locking
395+ [ 10 ] : https://en.wikipedia.org/wiki/Compare-and-swap
396+ [ 11 ] : https://github.com/php-lock/lock/blob/master/classes/mutex/CASMutex.php#L44
0 commit comments