11** [ Requirements] ( #requirements ) ** |
22** [ Installation] ( #installation ) ** |
3- ** [ Usage] ( #usage ) **
3+ ** [ Usage] ( #usage ) ** |
4+ ** [ License and authors] ( #license-and-authors ) ** |
5+ ** [ Donations] ( #donations ) **
46
57# php-lock/lock
68
@@ -17,73 +19,131 @@ php-lock/lock follows semantic versioning. Read more on [semver.org][1].
1719----
1820
1921## Requirements
22+
2023 - PHP 7.1 or above
21- - Optionally [ nrk/predis] ( https://github.com/nrk/predis ) to use the predis locks.
22- - Optionally the [ php-pcntl] ( http://php.net/manual/en/book.pcntl.php ) extension to enable locking with flock without busy waiting in CLI scripts.
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.
2327
2428----
2529
2630## Installation
2731
28- Use [ Composer] ( https://getcomposer.org/ ) :
32+ ### Composer
33+
34+ To use this library through [ composer] [ 4 ] , run the following terminal command
35+ inside your repository's root folder.
2936
3037``` sh
3138composer require " malkusch/lock"
3239```
3340
41+ As an alternative, you can directly add this library to your ` composer.json ` .
42+
43+ ``` json
44+ {
45+ "require" : {
46+ "malkusch/lock" : " ^1.4"
47+ }
48+ }
49+ ```
50+
51+ To use the newest (maybe unstable) version, use ` dev-master ` as the version in
52+ your ` composer.json ` .
53+
54+ ``` json
55+ {
56+ "require" : {
57+ "malkusch/lock" : " dev-master"
58+ }
59+ }
60+ ```
61+
3462## Usage
3563
36- The package is in the namespace
37- [ ` malkusch\lock ` ] ( http://malkusch.github.io/lock/api/namespace-malkusch.lock.html ) .
64+ This library uses the namespace ` malkusch\lock ` .
3865
3966### Mutex
4067
41- The
42- [ ` Mutex ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.Mutex.html )
43- provides the API for this library.
68+ The [ ` malkusch\lock\mutex\Mutex ` ] [ 5 ] class is an abstract class and provides the
69+ base API for this library.
4470
4571#### Mutex::synchronized()
4672
47- [ ` Mutex::synchronized() ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.Mutex.html#_synchronized )
48- executes code exclusively. This method guarantees that the code is only executed
49- by one process at once. Other processes have to wait until the mutex is available.
50- The critical code may throw an exception, which would release the lock as well.
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.
5181
5282Example:
83+
5384``` php
54- $mutex->synchronized(function () use ($bankAccount, $amount) {
85+ $newBalance = $ mutex->synchronized(function () use ($bankAccount, $amount) {
5586 $balance = $bankAccount->getBalance();
5687 $balance -= $amount;
5788 if ($balance < 0) {
58- throw new \DomainException("You have no credit.");
59-
89+ throw new \DomainException('You have no credit.');
6090 }
6191 $bankAccount->setBalance($balance);
92+
93+ return $balance;
6294});
6395```
6496
6597#### Mutex::check()
6698
67- [ ` Mutex::check() ` ] ( http://malkusch.github.io/lock/api/class-malkusch.lock.mutex.Mutex.html#_check )
68- performs a double-checked locking pattern. I.e. if the check fails, no lock
69- will be acquired. Else if the check was true, a lock will be acquired and the
70- check will be perfomed as well together with the critical code.
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.
106+
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.
71121
72122Example:
123+
73124``` php
74- $mutex->check(function () use ($bankAccount, $amount) {
125+ $newBalance = $ mutex->check(function () use ($bankAccount, $amount) {
75126 return $bankAccount->getBalance() >= $amount;
76-
77127})->then(function () use ($bankAccount, $amount) {
78128 $balance = $bankAccount->getBalance();
79129 $balance -= $amount;
80130 $bankAccount->setBalance($balance);
131+
132+ return $balance;
81133});
134+
135+ if (false === $newBalance) {
136+ if ($balance < 0) {
137+ throw new \DomainException('You have no credit.');
138+ }
139+ }
82140```
83141
84- #### Implementations
142+ ### Implementations
85143
86- 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.
87147
88148- [ ` CASMutex ` ] ( #casmutex )
89149- [ ` FlockMutex ` ] ( #flockmutex )
@@ -95,19 +155,18 @@ The `Mutex` is an abstract class. You will have to choose an implementation:
95155- [ ` MySQLMutex ` ] ( #mysqlmutex )
96156- [ ` PgAdvisoryLockMutex ` ] ( #pgadvisorylockmutex )
97157
158+ #### CASMutex
98159
99- ##### CASMutex
100-
101- The ** CASMutex**
102- has to be used with a [ Compare-and-swap] ( https://en.wikipedia.org/wiki/Compare-and-swap ) operation.
103- This mutex is lock free. It will repeat executing the code until the CAS operation was
104- successful. The code should therefore notify the mutex by calling
105- [ ` 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 ] .
106164
107- As the mutex keeps executing the critical code, it must not have any side effects
108- 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.
109167
110168Example:
169+
111170``` php
112171$mutex = new CASMutex();
113172$mutex->synchronized(function () use ($memcached, $mutex, $amount) {
@@ -121,7 +180,7 @@ $mutex->synchronized(function () use ($memcached, $mutex, $amount) {
121180});
122181```
123182
124- ##### FlockMutex
183+ #### FlockMutex
125184
126185The ** FlockMutex** is a lock implementation based on [ ` flock() ` ] ( http://php.net/manual/en/function.flock.php ) .
127186
@@ -139,10 +198,10 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
139198});
140199```
141200
142- Timeouts are supported as an optional second argument. This uses the pcntl extension if
143- 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.
144203
145- ##### MemcachedMutex
204+ #### MemcachedMutex
146205
147206The ** MemcachedMutex**
148207is a spinlock implementation which uses the [ ` Memcached ` API] ( http://php.net/manual/en/book.memcached.php ) .
@@ -164,7 +223,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
164223});
165224```
166225
167- ##### PHPRedisMutex
226+ #### PHPRedisMutex
168227
169228The ** PHPRedisMutex** is the distributed lock implementation of [ RedLock] ( http://redis.io/topics/distlock )
170229which uses the [ ` phpredis ` extension] ( https://github.com/phpredis/phpredis ) .
@@ -191,7 +250,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
191250});
192251```
193252
194- ##### PredisMutex
253+ #### PredisMutex
195254
196255The ** PredisMutex** is the distributed lock implementation of [ RedLock] ( http://redis.io/topics/distlock )
197256which uses the [ ` Predis ` API] ( https://github.com/nrk/predis ) .
@@ -212,7 +271,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
212271});
213272```
214273
215- ##### SemaphoreMutex
274+ #### SemaphoreMutex
216275
217276The ** SemaphoreMutex**
218277is a lock implementation based on [ Semaphore] ( http://php.net/manual/en/ref.sem.php ) .
@@ -232,7 +291,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
232291});
233292```
234293
235- ##### TransactionalMutex
294+ #### TransactionalMutex
236295
237296The ** TransactionalMutex**
238297delegates the serialization to the DBS. The exclusive code is executed within
@@ -261,7 +320,7 @@ $mutex->synchronized(function () use ($pdo, $accountId, $amount) {
261320});
262321```
263322
264- ##### MySQLMutex
323+ #### MySQLMutex
265324
266325The ** MySQLMutex** uses MySQL's
267326[ ` GET_LOCK ` ] ( https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_get-lock )
@@ -288,7 +347,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
288347});
289348```
290349
291- ##### PgAdvisoryLockMutex
350+ #### PgAdvisoryLockMutex
292351
293352The ** PgAdvisoryLockMutex** uses PostgreSQL's
294353[ advisory locking] ( https://www.postgresql.org/docs/9.4/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS )
@@ -324,4 +383,14 @@ Responsible for this project is Willem Stuursma-Ruwen <
[email protected] >.
324383If you like this project and feel generous donate a few Bitcoins here:
325384[ 1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA] ( bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA )
326385
327- [ 1 ] : http://semver.org/
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