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 )
1
12
[ ![ 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 )
2
14
3
15
This library helps executing critical code in concurrent situations.
4
16
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.
6
27
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.
8
36
9
37
``` sh
10
- composer require malkusch/lock
38
+ composer require " malkusch/lock"
11
39
```
12
40
13
- # Usage
41
+ As an alternative, you can directly add this library to your ` composer.json ` .
14
42
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
+ ```
17
50
18
- ## Mutex
51
+ To use the newest (maybe unstable) version, use ` dev-master ` as the version in
52
+ your ` composer.json ` .
19
53
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
23
67
24
- ### Mutex::synchronized()
68
+ The [ ` malkusch\lock\mutex\Mutex ` ] [ 5 ] class is an abstract class and provides the
69
+ base API for this library.
25
70
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.
30
81
31
82
Example:
83
+
32
84
``` php
33
- $mutex->synchronized(function () use ($bankAccount, $amount) {
85
+ $newBalance = $ mutex->synchronized(function () use ($bankAccount, $amount) {
34
86
$balance = $bankAccount->getBalance();
35
87
$balance -= $amount;
36
88
if ($balance < 0) {
37
- throw new \DomainException("You have no credit.");
38
-
89
+ throw new \DomainException('You have no credit.');
39
90
}
40
91
$bankAccount->setBalance($balance);
92
+
93
+ return $balance;
41
94
});
42
95
```
43
96
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.
45
106
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.
50
121
51
122
Example:
123
+
52
124
``` php
53
- $mutex->check(function () use ($bankAccount, $amount) {
125
+ $newBalance = $ mutex->check(function () use ($bankAccount, $amount) {
54
126
return $bankAccount->getBalance() >= $amount;
55
-
56
127
})->then(function () use ($bankAccount, $amount) {
57
128
$balance = $bankAccount->getBalance();
58
129
$balance -= $amount;
59
130
$bankAccount->setBalance($balance);
131
+
132
+ return $balance;
60
133
});
134
+
135
+ if (false === $newBalance) {
136
+ if ($balance < 0) {
137
+ throw new \DomainException('You have no credit.');
138
+ }
139
+ }
61
140
```
62
141
63
142
### Implementations
64
143
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.
66
147
67
148
- [ ` CASMutex ` ] ( #casmutex )
68
149
- [ ` FlockMutex ` ] ( #flockmutex )
@@ -74,19 +155,18 @@ The `Mutex` is an abstract class. You will have to choose an implementation:
74
155
- [ ` MySQLMutex ` ] ( #mysqlmutex )
75
156
- [ ` PgAdvisoryLockMutex ` ] ( #pgadvisorylockmutex )
76
157
77
-
78
158
#### CASMutex
79
159
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 ] .
85
164
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.
88
167
89
168
Example:
169
+
90
170
``` php
91
171
$mutex = new CASMutex();
92
172
$mutex->synchronized(function () use ($memcached, $mutex, $amount) {
@@ -118,8 +198,8 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
118
198
});
119
199
```
120
200
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.
123
203
124
204
#### MemcachedMutex
125
205
@@ -240,7 +320,6 @@ $mutex->synchronized(function () use ($pdo, $accountId, $amount) {
240
320
});
241
321
```
242
322
243
-
244
323
#### MySQLMutex
245
324
246
325
The ** MySQLMutex** uses MySQL's
@@ -267,6 +346,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
267
346
$bankAccount->setBalance($balance);
268
347
});
269
348
```
349
+
270
350
#### PgAdvisoryLockMutex
271
351
272
352
The ** PgAdvisoryLockMutex** uses PostgreSQL's
@@ -293,9 +373,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
293
373
});
294
374
```
295
375
296
-
297
-
298
- # License and authors
376
+ ## License and authors
299
377
300
378
This project is free and under the WTFPL.
301
379
Responsible for this project is Willem Stuursma-Ruwen
< [email protected] > .
@@ -305,4 +383,14 @@ Responsible for this project is Willem Stuursma-Ruwen <
[email protected] >.
305
383
If you like this project and feel generous donate a few Bitcoins here:
306
384
[ 1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA] ( bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA )
307
385
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