2018-04-15 14:41:46 +00:00
|
|
|
noccylabs/ipc
|
|
|
|
=============
|
|
|
|
|
|
|
|
This is a one-size-fits-all IPC library to facilitate communication between
|
2018-04-15 16:27:51 +00:00
|
|
|
threads and processes.
|
2018-04-15 14:41:46 +00:00
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
For complete examples, see the `examples` directory in the source tree.
|
2018-04-15 18:55:30 +00:00
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
## Signals
|
2018-04-15 14:41:46 +00:00
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
Asynchronous signals are automatically enabled if supported. Otherwise, the
|
|
|
|
`pcntl_signal_dispatch()` method must be frequently called from your main loop.
|
2018-04-15 18:55:30 +00:00
|
|
|
You can test for this using the `SIGNALS_ASYNC` constant:
|
2018-04-15 14:41:46 +00:00
|
|
|
|
2018-04-15 18:55:30 +00:00
|
|
|
if (!SIGNALS_ASYNC) {
|
2018-04-15 16:27:51 +00:00
|
|
|
pcntl_signal_dispatch();
|
|
|
|
}
|
2018-04-15 14:41:46 +00:00
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
### Signal handlers
|
2018-04-15 14:41:46 +00:00
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
Signal handlers allow for multiple listeners, with any one of them being able to
|
|
|
|
prevent the signal from bubbling up.
|
2018-04-15 14:41:46 +00:00
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
$handler = new SignalHandler(SIGUSR1);
|
|
|
|
|
|
|
|
$handler->addHandler(function () {
|
|
|
|
// Handle SIGUSR1, return true to stop bubbling
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
You can also handle as well as fire signals using the `Signal` class:
|
|
|
|
|
|
|
|
$signal = new Signal(SIGUSR1);
|
|
|
|
$signal->setHandler(function () {
|
|
|
|
// Handle SIGUSR1
|
|
|
|
});
|
|
|
|
|
|
|
|
// Dispatch the signal to ourselves
|
|
|
|
(new Signal(SIGUSR1))->dispatch($pid);
|
|
|
|
|
|
|
|
|
|
|
|
### Signal traps
|
|
|
|
|
|
|
|
Traps are used in the main loop to break on signals
|
|
|
|
|
|
|
|
$trap = new SignalTrap(SIGINT);
|
|
|
|
|
|
|
|
while (!$trap->isTrapped()) {
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
|
2018-04-15 16:39:10 +00:00
|
|
|
### Timers
|
2018-04-15 16:27:51 +00:00
|
|
|
|
|
|
|
Timers fire asynchronously at fixed 1 second intervals. It requires signals to be
|
|
|
|
processed; see above.
|
|
|
|
|
2018-04-15 16:39:10 +00:00
|
|
|
// Once every second...
|
2018-04-15 16:27:51 +00:00
|
|
|
$timer = new Timer(function () {
|
|
|
|
echo ".";
|
|
|
|
});
|
|
|
|
|
|
|
|
## File locks
|
|
|
|
|
|
|
|
File locks uses a shared file as a resource for locking.
|
|
|
|
|
2018-04-15 16:39:10 +00:00
|
|
|
// Creating the lock will not acquire it
|
|
|
|
$lock = new FileLock(__FILE__);
|
2018-04-15 16:27:51 +00:00
|
|
|
|
2018-04-15 16:39:10 +00:00
|
|
|
if (!$lock->acquire()) {
|
|
|
|
echo "fail!\n";
|
|
|
|
} else {
|
|
|
|
$lock->release();
|
|
|
|
}
|
2018-04-15 16:27:51 +00:00
|
|
|
|
|
|
|
## SysV wrappers
|
|
|
|
|
2018-04-15 16:39:10 +00:00
|
|
|
All these wrappers depend on a `KeyInterface` being passed to the constructor.
|
|
|
|
This is usually an instance of a `FileKey`, created as such:
|
|
|
|
|
|
|
|
$key = new FileKey(__FILE__);
|
|
|
|
|
|
|
|
The key has a project identifier that starts at `chr(0)`, or `"\0"`. To increase
|
|
|
|
this identifier, and thus point to another segment, just clone it.
|
|
|
|
|
|
|
|
$key2 = clone $key1;
|
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
### Semaphores
|
|
|
|
|
2018-04-15 18:52:49 +00:00
|
|
|
Semaphores are created with a key and a max count.
|
|
|
|
|
|
|
|
$key = new FileKey(__FILE__);
|
|
|
|
$sem = new Semaphore($key, 2);
|
|
|
|
|
|
|
|
$sem->allocate(); // -> true
|
|
|
|
$sem->allocate(); // -> true
|
|
|
|
$sem->allocate(); // -> false
|
|
|
|
$sem->release();
|
|
|
|
|
|
|
|
$mutex->destroy();
|
|
|
|
|
2018-04-15 16:27:51 +00:00
|
|
|
### Mutexes
|
|
|
|
|
2018-04-15 18:52:49 +00:00
|
|
|
A mutex is a semaphore with a max count of 1.
|
|
|
|
|
|
|
|
$key = new FileKey(__FILE__);
|
|
|
|
$mutex = new Mutex($key);
|
|
|
|
|
|
|
|
$mutex->allocate(); // -> true
|
|
|
|
$mutex->allocate(); // -> false
|
|
|
|
$mutex->release();
|
|
|
|
|
|
|
|
$mutex->destroy();
|
|
|
|
|
2018-04-15 16:39:10 +00:00
|
|
|
### Message Queues
|
|
|
|
|
|
|
|
$key = new FileKey(__FILE__);
|
|
|
|
$msgq = new Queue($key);
|
|
|
|
|
|
|
|
$msgq->send(1, [ "Some data", [ "format"=>"foo" ]]);
|
|
|
|
|
|
|
|
$data = $msgq->receive(1, $type);
|
|
|
|
|
|
|
|
$msgq->destroy();
|
|
|
|
|
|
|
|
### Shared Memory
|
|
|
|
|
|
|
|
Shared memory using `SharedData` supports integrity checking when setting, using
|
|
|
|
the third parameter to `set()`.
|
|
|
|
|
|
|
|
$key = new FileKey(__FILE__);
|
|
|
|
$shm = new SharedData($key);
|
|
|
|
|
|
|
|
do {
|
|
|
|
$counter = $shm->get("counter") + 1;
|
|
|
|
} while (!$shm->set("counter", $counter, true));
|
|
|
|
|
|
|
|
$shm->destroy();
|
|
|
|
|
|
|
|
The `SharedMemory` class is a simple integer-indexed array
|
|
|
|
|
|
|
|
$key = new FileKey(__FILE__);
|
|
|
|
$shm = new SharedMemory($key);
|
|
|
|
|
|
|
|
$shm[0] = 42;
|
|
|
|
|
|
|
|
$shm->destroy();
|
2018-04-15 16:27:51 +00:00
|
|
|
|
|
|
|
## Communication
|
|
|
|
|
|
|
|
### Channels
|
|
|
|
|
|
|
|
Channels are essentially connected pipes. A channel can be created with a stream resource,
|
|
|
|
or through the `createPair()` factory method.
|
|
|
|
|
|
|
|
[ $ch1, $ch2 ] = StreamChannel::createPair();
|
|
|
|
$ch1->send($data);
|
|
|
|
$rcvd = $ch2->receive();
|