E/S sin bloqueo con tuberías en C

Requisito previo: llamada al sistema pipe()
¿Cuándo ocurre el bloque de E/S en pipe()?  
Considere dos procesos, un proceso que recopila datos (leer datos) en tiempo real y otro proceso que los traza (escribir datos). Los dos procesos están conectados por una tubería, y el proceso de adquisición de datos alimenta el proceso de trazado de datos. La velocidad de adquisición de datos de dos procesos es diferente. 
El comportamiento predeterminado en una tubería es que los extremos de escritura y lectura de una tubería muestren un comportamiento de bloqueo, si el proceso asociado es más lento. Esto es malo porque el proceso de adquisición de datos puede esperar en el proceso de trazado (escribir datos). Entonces, durante el proceso de adquisición de datos, bloquee la llamada de lectura en la canalización y el programa se cuelga. Si queremos que esto no suceda, debemos cerrar el final de escritura en proceso antes de la llamada de final de lectura. 
En un lenguaje sencillo,  

  • Una llamada de lectura obtiene tantos datos como solicita o tantos datos como tiene la canalización, lo que sea menor
  • Si la tubería está vacía 
    • Las lecturas en la tubería devolverán EOF (valor de retorno 0) si ningún proceso tiene el extremo de escritura abierto
    • Si algún proceso tiene la tubería abierta para escribir, la lectura se bloqueará en previsión de nuevos datos

E/S sin bloqueo con tuberías

A veces es conveniente tener E/S que no se bloqueen, es decir, no queremos que una llamada de lectura se bloquee en uno en caso de entrada desde el otro. La solución para esto es la función dada: 

  To specify non-blocking option:
       #include<fcntl.h> 
       int fd; 
       fcntl(fd, F_SETFL, O_NONBLOCK); 
  • fd: descriptor de archivo
  • F_SETFL: establezca los indicadores de estado del archivo en el valor especificado por arg. El modo de acceso a archivos aquí en nuestro propósito se usa solo para el indicador O_NONBLOCK .
  • O_NONBLOCK: uso para la opción de no bloqueo.
  • 0: retorno en éxito
  • -1: volver en caso de error, establecer errorno

Después de que esta función se ejecuta con éxito, una llamada a lectura/escritura devuelve -1 si la tubería 
está vacía/llena y establece errno en EAGAIN
Ejemplo: el niño escribe «hola» al padre cada 3 segundos y el padre hace una lectura sin bloqueo cada segundo.
 

C

// C program to illustrate
// non I/O blocking calls
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h> // library for fcntl function
#define MSGSIZE 6
char* msg1 =“hello”;
char* msg2 =“bye !!”;
 
int main()
{
    int p[2], i;
 
    // error checking for pipe
    if (pipe(p) < 0)
        exit(1);
 
    // error checking for fcntl
    if (fcntl(p[0], F_SETFL, O_NONBLOCK) < 0)
        exit(2);
 
    // continued
    switch (fork()) {
 
    // error
    case -1:
        exit(3);
 
    // 0 for child process
    case 0:
        child_write(p);
        break;
 
    default:
        parent_read(p);
        break;
    }
    return 0;
}
void parent_read(int p[])
{
    int nread;
    char buf[MSGSIZE];
 
    // write link
    close(p[1]);
 
    while (1) {
 
        // read call if return -1 then pipe is
        // empty because of fcntl
        nread = read(p[0], buf, MSGSIZE);
        switch (nread) {
        case -1:
 
            // case -1 means pipe is empty and errono
            // set EAGAIN
            if (errno == EAGAIN) {
                printf(“(pipe empty)\n”);
                sleep(1);
                break;
            }
 
            else {
                perror(“read”);
                exit(4);
            }
 
        // case 0 means all bytes are read and EOF(end of conv.)
        case 0:
            printf(“End of conversation\n”);
 
            // read link
            close(p[0]);
 
            exit(0);
        default:
 
            // text read
            // by default return no. of bytes
            // which read call read at that time
            printf(“MSG = % s\n”, buf);
        }
    }
}
void child_write(int p[])
{
    int i;
 
    // read link
    close(p[0]);
 
    // write 3 times "hello" in 3 second interval
    for (i = 0; i < 3; i++) {
        write(p[1], msg1, MSGSIZE);
        sleep(3);
    }
 
    // write "bye" one times
    write(p[1], msg2, MSGSIZE);
 
    // here after write all bytes then write end
    // doesn't close so read end block but
    // because of fcntl block doesn't happen..
    exit(0);
}

Producción: 

(pipe empty)
MSG=hello
(pipe empty)
(pipe empty)
(pipe empty)
MSG=hello
(pipe empty)
(pipe empty)
(pipe empty)
MSG=hello
(pipe empty)
(pipe empty)
(pipe empty)
MSG=bye!!
End of conversation

Escrituras atómicas en tubería

Atómico significa que ningún otro proceso observa que está parcialmente hecho. Leer o escribir datos de tubería es atómico si el tamaño de los datos escritos no es mayor que PIPE_BUF(4096 bytes) . Esto significa que la transferencia de datos parece ser una unidad instantánea, lo que significa que nada más en el sistema puede observar un estado en el que está parcialmente completo. Es posible que la E/S atómica no comience de inmediato (es posible que deba esperar el espacio del búfer o los datos), pero una vez que comienza, finaliza de inmediato.
Las escrituras de datos de hasta PIPE_BUF (4096 bytes) son atómicas. Leer o escribir una mayor cantidad de datos puede no ser atómico; Por ejemplo, se pueden intercalar datos de salida de otros procesos que comparten el descriptor. Además, una vez que PIPE_BUFse han escrito caracteres, las escrituras adicionales se bloquearán hasta que se lean algunos caracteres
Ejemplo: el proceso 1 envía un mensaje de 100 bytes al mismo tiempo, el proceso 2 envía un mensaje de 100 bytes No hay garantía sobre el pedido, pero la canalización recibirá todo de uno mensaje seguido de todos los demás.
En escrituras no atómicas para escrituras más grandes no existe tal garantía, los datos podrían entremezclarse de manera confusa como esta: 
 

Capacidad de tubería

  • Una tubería puede contener un número limitado de bytes.
  • Escribe llenar la tubería y bloquear cuando la tubería está llena 
    • Se bloquean hasta que otro proceso lee suficientes datos en el otro extremo de la tubería y regresan cuando se han transmitido todos los datos dados para escribir.
  • La capacidad de una tubería es de al menos 512 bytes, generalmente más (depende del sistema)

C

// C program to illustrate
// finding capacity of pipe
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int count = 0;
 
// SIGALRM signal handler
void alrm_action(int signo)
{
    printf("Write blocked after %d characters\n", count);
    exit(0);
}
int main()
{
    int p[2];
    char c = 'x';
 
    // SIGALRM signal
    signal(SIGALRM, alrm_action);
 
    // pipe error check
    if (pipe(p) == -1)
        exit(1);
 
    while (1) {
        alarm(5);
 
        // write 'x' at one time when capacity full
        // write() block and after 5 second alarm
        write(p[1], &c, 1);
 
        // send signal and alrm_action handler execute.
        ++count;
        alarm(0);
    }
}

Producción: 

Write blocked after 65536 characters 
//output depend on the system so output may change in different system

Aquí, en el ciclo while, la primera alarma de 5 segundos se establece después de que la llamada write() escribe un carácter ‘x’ en la tubería. Y la variable de conteo se usa para escribir caracteres de conteo en la tubería. strong> alarm(0) significa cancelar la alarma establecida de 5 segundos. Después de un tiempo, cuando la capacidad de la tubería está llena, la llamada write() se bloquea y el programa no ejecuta la siguiente instrucción, después de 5 segundos, configure el timbre de alarma y envíe la señal SIGALRM . Después de que el controlador alram_action se ejecuta e imprime cuántos caracteres máximos se pueden escribir por canalización. 
Este artículo es una contribución de Kadam Patel. Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *