$ ./a.out w5 s1 w5 s1 w 50000w50 | ./a.out r | ./a.out r1 check r & ps -ef | grep a.out
[3] 840810908
ale 840610906 8066 0 1910:3324 pts/6 00:00:00 ./a.out w5 s1 w5 s1 w 50000w50
ale 840710907 8066 0 1910:3324 pts/6 00:00:00 ./a.out r
ale 840810908 8066 0 1910:3324 pts/6 00:00:00 ./a.out r1 check r
ale 841010910 8066 0 1910:3324 pts/6 00:00:00 grep a.out
$ 2025-03-03T1904T10:3324:5056.616080+01628434+01:00 pcale dummy pipe[8406]pipe[10906]: exiting (read 0 bytes)
2025-03-03T1904T10:3324:5056.616455+01628925+01:00 pcale dummy pipe[8407]pipe[10907]: exiting (read 2769 bytes)
2025-03-03T1904T10:3324:5056.616691+01629188+01:00 pcale dummy pipe[8408]pipe[10908]: kill 840610906: No such process
2025-03-03T1904T10:3324:5056.616843+01629377+01:00 pcale dummy pipe[8408]pipe[10908]: exiting (read 2769 bytes)
That is, by the time the third instance starts reading, the first one has already finished, despite the time it spent sleeping and the huge amount it writes. This means that at some point all of those 502,000769 bytes rows are stored together.
Increasing the amount of data, as Scott noted, concurrency enters.
$ ./a.out w5 s1 w5 s1 w150 | ./a.out r | ./a.out r1 check r & ps -ef | grep a.out
[3] 11254
ale 11252 8066 0 10:31 pts/6 00:00:00 ./a.out w5 s1 w5 s1 w150
ale 11253 8066 0 10:31 pts/6 00:00:00 ./a.out r
ale 11254 8066 0 10:31 pts/6 00:00:00 ./a.out r1 check r
ale 11256 8066 0 10:31 pts/6 00:00:00 grep a.out
$ 2025-03-04T10:31:13.002766+01:00 pcale dummy pipe[11252]: exiting (read 0 bytes)
2025-03-04T10:31:13.003068+01:00 pcale dummy pipe[11254]: kill 11252: still running
2025-03-04T10:31:13.003235+01:00 pcale dummy pipe[11253]: exiting (read 7569 bytes)
2025-03-04T10:31:13.003502+01:00 pcale dummy pipe[11254]: exiting (read 7569 bytes)
I tried to determine by dichotomic search the value that triggers the buffering strategy, but couldn't. It changes from time to time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <limits.h>
static void do_open(void)
{
openlog("dummy pipe", LOG_PID, LOG_USER);
}
int main(int argc, char *argv[])
{
do_open();
pid_t me = 1;
int wrote = 0, n;
long total_read = 0;
for (int i = 1; i < argc; ++i)
{
if (argv[i][0] == 'w' && (n = atoi(&argv[i][1])) > 0)
{
if (wrote == 0)
{
me = getpid();
setsid();
wrote = 1;
}
if (n --> 0)
printf("Pid: %d\n", me);
while (n --> 0)
puts("Lorem ipsum lorem ipsum lorem ipsum lorem ipsum");
}
else if (argv[i][0] == 's' && (n = atoi(&argv[i][1])) > 0)
sleep(n);
else if (argv[i][0] == 'r')
{
if (argv[i][1] == 0)
n = INT_MAX;
else
n = atoi(&argv[i][1]);
char buf[1024];
while (n --> 0)
{
char *p = fgets(buf, sizeof buf, stdin);
if (p == NULL)
break;
if (buf[0] == 'P')
sscanf(buf, "Pid: %d\n", &me);
total_read += strlen(buf);
if (!isatty(fileno(stdout)))
printf("%s", buf);
}
}
else if (strcmp(argv[i], "check") == 0)
{
if (me != 1)
{
n = kill(me, 0);
syslog(LOG_NOTICE, "kill %d: %s\n", me,
n? strerror(errno): "still running");
closelog();
do_open();
}
}
}
syslog(LOG_NOTICE, "exiting\n""exiting (read %'ld bytes)\n", total_read);
closelog();
return 0;
}