Taking an exact number of bytes from input in C and synchronization between processes

57 Views Asked by At

Hi i need to take only 5 bytes from stdin, i've tried this but i have problem while executing it since it keeps asking me for input and at the end the string contained in buffer is wrong. Also i'd like to know how to synchronize N processes while the parent is sleeping.

buffers[] is an array of buffers.

#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fflush(stdin) while (getchar() != '\n')

char **filenames;
int *files;
char **buffers;
int n_proc;

int main(int argc, char **argv) {
    long i;
    pid_t pid;
    int status;

    if(argc < 2) {
        puts("Usage error: prog file1 ... fileN.\n");
        exit(1);
    }

    filenames = argv + 1;

    n_proc = argc - 1;

    puts("Bef malloc buff.\n");

    if((buffers = malloc(sizeof(char *) * n_proc)) == NULL) {
        puts("Buffers' malloc error.\n");
        exit(1);
    }

    if((files = malloc(sizeof(int) * n_proc)) == NULL) {
        puts("Files' malloc error.\n");
        exit(1);
    }

    puts("After malloc buff.\n");

    for(i = 0; i < n_proc; i++) {
        if((files[i] = open(filenames[i], O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
            printf("Error while opening file %ld.\n", i);
            exit(1);
        }
    }

    puts("After file open.\n");

    for(i = 0; i < n_proc; i++) {
        if((buffers[i] = (char *) mmap(NULL, 1028, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0)) == NULL) {
            printf("Error in mapping buffer %ld.\n", i);
            exit(1);
        }
    }

    puts("After mapping.\n");

    i = 0;

    while(i < n_proc) {

        printf("Fork %ld started.\n", i);

        pid = fork();

        if(pid < 0) {
            printf("Error while forking %ld.\n", i);
            exit(1);
        } else if(pid == 0) {

            puts("Please insert an input of max 5 characters.\n");

            printf("Son %ld.\n", i);

            fflush(stdout);

            fgets(buffers[i], 6, stdin);

            buffers[i][strcspn(buffers[i], "\n")] = 0;

            //int j;

            //for(j = 0; j < 5; j++)
                  //buffers[i][j] = getchar();

            //printf("Buff has %s inside.\n", buff);

            //fflush(stdout);

            fflush(stdin);

            //strcpy(buffers[i], buff);

            printf("Buffer %d has string %s inside.\n", i, buffers[i]);

            fflush(stdout);

            write(files[i], buffers[i], 6);
        } else {
            printf("Parent %ld.\n", i);
            wait(&status);
        }

        i++;
    }


}

This is only a prototype of the code, since there's still synchronization needed and signal handling

Code requires when to write on command line N files and creating N processes that each take 5 bytes from stdin and put in their own file.

As an example if i try with

./a.out hello.txt hello1.txt

Bef malloc buff.

After malloc buff.

After file open.

After mapping.

Fork 0 started.
Parent 0.
Please insert an input of max 5 characters.

Son 0.
Hello
Hello
Buffer 0 has string Hello inside.
Hello
Fork 1 started.
Parent 1.
Please insert an input of max 5 characters.

Son 1.
Hello
Hello
Buffer 1 has string Hello inside.
Hello
Fork 1 started.
Parent 1.
Please insert an input of max 5 characters.

Son 1.

As you can see it doesn't take the input and keeps asking for it, same problem with the getchar().

1

There are 1 best solutions below

6
Allan Wind On

Note that in case stdin is associated with a terminal, there may also be input buffering in the terminal driver, entirely unrelated to stdio buffering. (Indeed, normally terminal input is line buffered in the kernel.) This kernel input handling can be modified using calls like tcsetattr(3); (stdin(3) man page)

If you give it the input "12345\n":

#include <stdio.h>

int main(void) {
    char buffers[1][5];
    unsigned i = 0;
    for(unsigned j = 0; j < 5; j++)
        buffers[i][j] = getchar();
    printf("%.5s", buffers[i]);
    // read the newline.  You may need to discard others.
    int ch = getchar();
    if(ch == '\n')
        printf("\n");
    return 0;
}

it will print:

12345