In the default case of 20, the code sleeps for 1, 2, 3, 5, 8, and 13 seconds for a total delay of 32 seconds before it failes. (The next sleep value would be 21, which exceeds the stall parameter.)
This is cool for double-buffered I/O, rendering of tiled data (such as maps, or video frames), or finite element analysis. Any problem that requires synchronization with a fixed, repeated order will fit the pipe-ring gang paradigm.
Scaling a ring when you find more processors on a host just makes the ring a little bigger, no code changes.
extern int PipeRing(int (*pfiTask)(), int iCount, void *pvData, int *piRet, char *pcStart);
fork
ing Count child
processes with pipes between them. The C function Task is
declared (in detail) as
int (*pfiTask)(int iWorker, int iFdIn, int iFdOut, void *pvData);
Where FdIn is a descriptor on the "up stream" process, and FdOut
is a descriptor on the "down stream" process. In the case where there
is a gang-of-1 these are two ends of the same pipe. The Worker interger
represents the workers position in the ring, it is an
interger from 0 to (iCount-1).
The Data pointer is passed as a parameter to
each worker as presented to the ring-builder.
This could be a vector which might be indexed in the worker.
It is strongly suggested that an explicit (void *)0
be passed if the parameter is unused in the Task function.
If the ring-build fails each Worker will see an EOF on the first read of the FdIn pipe. This only happens when the builder process ran out of resources (viz. pipes or processes). As a best practice, the Task code should send some token around the pipe ring (once) to be certian a stable gang has been established. This is why the Start string is injected into the ring by the builder, after a successful ring construction.
extern int PipePump(int iWorker, int fdIn, int fdOut, void *pvData);
(void *)0
it must be a
(int *)
to the number of bytes to copy in each worker.
explode -s pipering.h
explode pipering.c
more piperingtest.c
$Id: pipering.html,v 1.8 2012/03/21 16:15:05 ksb Exp $