RosettaCodeData/Task/Synchronous-concurrency/C/synchronous-concurrency.c

113 lines
2.3 KiB
C

#include <stdlib.h> /* malloc(), realloc(), free() */
#include <stdio.h> /* fopen(), fgetc(), fwrite(), printf() */
#include <libco.h> /* co_create(), co_switch() */
void
fail(const char *message) {
perror(message);
exit(1);
}
/*
* These are global variables of this process. All cothreads of this
* process will share these global variables.
*/
cothread_t reader;
cothread_t printer;
struct {
char *buf; /* Not a C string. No terminating '\0'. */
size_t len; /* Length of line in buffer. */
size_t cap; /* Maximum capacity of buffer. */
} line;
size_t count; /* Number of lines printed. */
/*
* The reader cothread reads every line of an input file, passes each
* line to the printer cothread, and reports the number of lines.
*/
void
reader_entry(void)
{
FILE *input;
size_t newcap;
int c, eof, eol;
char *newbuf;
input = fopen("input.txt", "r");
if (input == NULL)
fail("fopen");
line.buf = malloc(line.cap = 4096); /* New buffer. */
if (line.buf == NULL)
fail("malloc");
line.len = 0; /* Start with an empty line. */
do {
c = fgetc(input); /* Read next character. */
if (ferror(input))
fail("fgetc");
eof = (c == EOF);
if (eof) {
/*
* End of file is also end of line,
` * unless the line would be empty.
*/
eol = (line.len > 0);
} else {
/* Append c to the buffer. */
if (line.len == line.cap) {
/* Need a bigger buffer! */
newcap = line.cap * 2;
newbuf = realloc(line.buf, newcap);
if (newbuf == NULL)
fail("realloc");
line.buf = newbuf;
line.cap = newcap;
}
line.buf[line.len++] = c;
/* '\n' is end of line. */
eol = (c == '\n');
}
if (eol) {
/* Pass our complete line to the printer. */
co_switch(printer);
line.len = 0; /* Destroy our line. */
}
} while (!eof);
free(line.buf);
line.buf = NULL; /* Stops a loop in the printer. */
printf("Printed %zu lines.\n", count);
co_switch(printer);
}
/*
* The printer cothread starts the reader cothread, prints every line
* line from the reader cothread, and counts the number of lines.
*/
int
main()
{
reader = co_create(4096, reader_entry);
printer = co_active();
count = 0;
for (;;) {
co_switch(reader);
if (line.buf == NULL)
break;
/* Print this line. Count it. */
fwrite(line.buf, 1, line.len, stdout);
count++;
}
co_delete(reader);
return 0;
}