Skip to content

Commit b2af0ca

Browse files
Merge branch 'develop' of github.com:TheLevti/lock into develop
2 parents bffc5c2 + 6fe1f1b commit b2af0ca

File tree

1 file changed

+113
-44
lines changed

1 file changed

+113
-44
lines changed

README.md

Lines changed: 113 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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
3138
composer 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

5282
Example:
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

72122
Example:
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

110168
Example:
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

126185
The **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

147206
The **MemcachedMutex**
148207
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) {
164223
});
165224
```
166225

167-
##### PHPRedisMutex
226+
#### PHPRedisMutex
168227

169228
The **PHPRedisMutex** is the distributed lock implementation of [RedLock](http://redis.io/topics/distlock)
170229
which 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

196255
The **PredisMutex** is the distributed lock implementation of [RedLock](http://redis.io/topics/distlock)
197256
which 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

217276
The **SemaphoreMutex**
218277
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) {
232291
});
233292
```
234293

235-
##### TransactionalMutex
294+
#### TransactionalMutex
236295

237296
The **TransactionalMutex**
238297
delegates 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

266325
The **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

293352
The **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]>.
324383
If 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

Comments
 (0)