<?php
declare(strict_types=1);
namespace malkusch\lock\mutex;
use malkusch\lock\util\DoubleCheckedLocking;
/**
* The mutex provides methods for exclusive execution.
*
* @author Markus Malkusch <markus@malkusch.de>
* @link bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA Donations
* @license WTFPL
*/
abstract class Mutex
{
/**
* Executes a block of code exclusively.
*
* This method implements Java's synchronized semantic. I.e. this method
* waits until a lock could be acquired, executes the code exclusively and
* releases the lock.
*
* The code block may throw an exception. In this case the lock will be
* released as well.
*
* @param callable $code The synchronized execution callback.
* @throws \Exception The execution callback threw an exception.
* @throws \malkusch\lock\exception\LockAcquireException The mutex could not
* be acquired, no further side effects.
* @throws \malkusch\lock\exception\LockReleaseException The mutex could not
* be released, the code was already executed.
* @throws \malkusch\lock\exception\ExecutionOutsideLockException Some code
* has been executed outside of the lock.
* @return mixed The return value of the execution callback.
*/
abstract public function synchronized(callable $code);
/**
* Performs a double-checked locking pattern.
*
* Call {@link \malkusch\lock\util\DoubleCheckedLocking::then()} on the
* returned object.
*
* Example:
* <code>
* $result = $mutex->check(function () use ($bankAccount, $amount) {
* return $bankAccount->getBalance() >= $amount;
* })->then(function () use ($bankAccount, $amount) {
* return $bankAccount->withdraw($amount);
* });
* </code>
*
* @param callable $check Callback that decides if the lock should be
* acquired and if the synchronized callback should be executed after
* acquiring the lock.
* @return \malkusch\lock\util\DoubleCheckedLocking The double-checked
* locking pattern.
*/
public function check(callable $check): DoubleCheckedLocking
{
return new DoubleCheckedLocking($this, $check);
}
}