1
1
** [ Requirements] ( #requirements ) ** |
2
2
** [ Installation] ( #installation ) ** |
3
- ** [ Usage] ( #usage ) **
3
+ ** [ Usage] ( #usage ) ** |
4
+ ** [ License and authors] ( #license-and-authors ) ** |
5
+ ** [ Donations] ( #donations ) **
4
6
5
7
# php-lock/lock
6
8
@@ -17,73 +19,131 @@ php-lock/lock follows semantic versioning. Read more on [semver.org][1].
17
19
----
18
20
19
21
## Requirements
22
+
20
23
- 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.
23
27
24
28
----
25
29
26
30
## Installation
27
31
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.
29
36
30
37
``` sh
31
38
composer require " malkusch/lock"
32
39
```
33
40
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
+
34
62
## Usage
35
63
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 ` .
38
65
39
66
### Mutex
40
67
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.
44
70
45
71
#### Mutex::synchronized()
46
72
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.
51
81
52
82
Example:
83
+
53
84
``` php
54
- $mutex->synchronized(function () use ($bankAccount, $amount) {
85
+ $newBalance = $ mutex->synchronized(function () use ($bankAccount, $amount) {
55
86
$balance = $bankAccount->getBalance();
56
87
$balance -= $amount;
57
88
if ($balance < 0) {
58
- throw new \DomainException("You have no credit.");
59
-
89
+ throw new \DomainException('You have no credit.');
60
90
}
61
91
$bankAccount->setBalance($balance);
92
+
93
+ return $balance;
62
94
});
63
95
```
64
96
65
97
#### Mutex::check()
66
98
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.
71
121
72
122
Example:
123
+
73
124
``` php
74
- $mutex->check(function () use ($bankAccount, $amount) {
125
+ $newBalance = $ mutex->check(function () use ($bankAccount, $amount) {
75
126
return $bankAccount->getBalance() >= $amount;
76
-
77
127
})->then(function () use ($bankAccount, $amount) {
78
128
$balance = $bankAccount->getBalance();
79
129
$balance -= $amount;
80
130
$bankAccount->setBalance($balance);
131
+
132
+ return $balance;
81
133
});
134
+
135
+ if (false === $newBalance) {
136
+ if ($balance < 0) {
137
+ throw new \DomainException('You have no credit.');
138
+ }
139
+ }
82
140
```
83
141
84
- #### Implementations
142
+ ### Implementations
85
143
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.
87
147
88
148
- [ ` CASMutex ` ] ( #casmutex )
89
149
- [ ` FlockMutex ` ] ( #flockmutex )
@@ -95,19 +155,18 @@ The `Mutex` is an abstract class. You will have to choose an implementation:
95
155
- [ ` MySQLMutex ` ] ( #mysqlmutex )
96
156
- [ ` PgAdvisoryLockMutex ` ] ( #pgadvisorylockmutex )
97
157
158
+ #### CASMutex
98
159
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 ] .
106
164
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.
109
167
110
168
Example:
169
+
111
170
``` php
112
171
$mutex = new CASMutex();
113
172
$mutex->synchronized(function () use ($memcached, $mutex, $amount) {
@@ -121,7 +180,7 @@ $mutex->synchronized(function () use ($memcached, $mutex, $amount) {
121
180
});
122
181
```
123
182
124
- ##### FlockMutex
183
+ #### FlockMutex
125
184
126
185
The ** FlockMutex** is a lock implementation based on [ ` flock() ` ] ( http://php.net/manual/en/function.flock.php ) .
127
186
@@ -139,10 +198,10 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
139
198
});
140
199
```
141
200
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.
144
203
145
- ##### MemcachedMutex
204
+ #### MemcachedMutex
146
205
147
206
The ** MemcachedMutex**
148
207
is 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) {
164
223
});
165
224
```
166
225
167
- ##### PHPRedisMutex
226
+ #### PHPRedisMutex
168
227
169
228
The ** PHPRedisMutex** is the distributed lock implementation of [ RedLock] ( http://redis.io/topics/distlock )
170
229
which uses the [ ` phpredis ` extension] ( https://github.com/phpredis/phpredis ) .
@@ -191,7 +250,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
191
250
});
192
251
```
193
252
194
- ##### PredisMutex
253
+ #### PredisMutex
195
254
196
255
The ** PredisMutex** is the distributed lock implementation of [ RedLock] ( http://redis.io/topics/distlock )
197
256
which uses the [ ` Predis ` API] ( https://github.com/nrk/predis ) .
@@ -212,7 +271,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
212
271
});
213
272
```
214
273
215
- ##### SemaphoreMutex
274
+ #### SemaphoreMutex
216
275
217
276
The ** SemaphoreMutex**
218
277
is a lock implementation based on [ Semaphore] ( http://php.net/manual/en/ref.sem.php ) .
@@ -232,7 +291,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
232
291
});
233
292
```
234
293
235
- ##### TransactionalMutex
294
+ #### TransactionalMutex
236
295
237
296
The ** TransactionalMutex**
238
297
delegates the serialization to the DBS. The exclusive code is executed within
@@ -261,7 +320,7 @@ $mutex->synchronized(function () use ($pdo, $accountId, $amount) {
261
320
});
262
321
```
263
322
264
- ##### MySQLMutex
323
+ #### MySQLMutex
265
324
266
325
The ** MySQLMutex** uses MySQL's
267
326
[ ` 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) {
288
347
});
289
348
```
290
349
291
- ##### PgAdvisoryLockMutex
350
+ #### PgAdvisoryLockMutex
292
351
293
352
The ** PgAdvisoryLockMutex** uses PostgreSQL's
294
353
[ 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] >.
324
383
If you like this project and feel generous donate a few Bitcoins here:
325
384
[ 1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA] ( bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA )
326
385
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