2011-05-02 18 views
6

Dispersión-recopilar - readv()/writev()/preadv()/pwritev() - lecturas/escrituras un número variable de estructuras iovec en una sola llamada al sistema. Básicamente lee/escribe cada buffer de forma secuencial desde el 0 ° iovec hasta el N °. Sin embargo, según la documentación, también puede devolver menos en las llamadas de lectura/escritura de lo solicitado. Me preguntaba si existe una forma estándar/mejor práctica/elegante para manejar esa situación.Técnicas para manejar lecturas cortas/escrituras con scatter-gather?

Si sólo estamos manejando un grupo de buffers de caracteres o similar, esto no es un gran problema. Pero una de las sutilezas es usar scatter-gather para estructuras y/o variables discretas como elementos individuales de iovec. ¿Cómo se maneja la situación en la que readv/writev solo lee/escribe una parte de una estructura o la mitad de una larga o algo así?

A continuación se muestra un código artificial de lo que quiero decir:

int fd; 

struct iovec iov[3]; 

long aLong = 74775767; 
int aInt = 949; 
char aBuff[100]; //filled from where ever 

ssize_t bytesWritten = 0; 
ssize_t bytesToWrite = 0; 

iov[0].iov_base = &aLong; 
iov[0].iov_len = sizeof(aLong); 
bytesToWrite += iov[0].iov_len; 

iov[1].iov_base = &aInt; 
iov[1].iov_len = sizeof(aInt); 
bytesToWrite += iov[1].iov_len; 

iov[2].iov_base = &aBuff; 
iov[2].iov_len = sizeof(aBuff); 
bytesToWrite += iov[2].iov_len; 

bytesWritten = writev(fd, iov, 3); 

if (bytesWritten == -1) 
{ 
    //handle error 
} 

if (bytesWritten < bytesToWrite) 
    //how to gracefully continue?......... 

Respuesta

11

utilizar un bucle como el siguiente para avanzar en la iov parcialmente procesada-:

for (;;) { 
    written = writev(fd, iov+cur, count-cur); 
    if (written < 0) goto error; 
    while (cur < count && written >= iov[cur].iov_len) 
     written -= iov[cur++].iov_len; 
    if (cur == count) break; 
    iov[cur].iov_base = (char *)iov[cur].iov_base + written; 
    iov[cur].iov_len -= written; 
} 

Tenga en cuenta que si no se comprueba para cur < count va a leer más allá del final de iov que puede contener cero.

+0

Bien, R, eso es exactamente lo que estaba buscando. Puntero aritmético al rescate. ¿Considera que los resultados cortos de lectura/escritura son una condición común en lugar de una excepción, como en la lectura/escritura estándar y esto es algo que siempre debe codificarse? – ValenceElectron

+2

Sí. Con pipes, Sockets o ttys en modo nonblocking, las escrituras cortas son la norma. Pero incluso en otras situaciones, pueden ser poco probable, pero aún una posibilidad real. Incluso si 'SA_RESTART' se usa para el manejador de señal, si' writev' es interrumpido por una señal, solo se reiniciará si aún no se ha escrito nada. Si ya se completó una escritura parcial, devolverá la escritura corta. Incluso si no tiene controladores de señal, el proceso se detiene y se reanuda con 'SIGSTOP' (no bloqueable) y' SIGCONT' tendrá los mismos efectos. –

+0

Por cierto, acabo de arreglar mi código. Olvidé que 'iov_base' tiene el tipo' void * 'y, por lo tanto, la aritmética no es válida. La nueva versión se convierte en 'char *' para realizar la aritmética. –

-1

escritura Vectored escribirá todos los datos que ha proporcionado con una llamada a la función "writev". Así, el octeto escrito siempre será igual al número total de bytes proporcionados como entrada. esto es lo que yo entiendo

Por favor, corríjanme si me equivoco

+0

Si el medio que está escribiendo se queda sin espacio antes de que todos los datos se escriben, los bytes escritos habrá menos de los bytes solicitados. –

+0

Para eso, de acuerdo con las páginas del manual de Unix, debería aparecer el error "EDQUOT". – Arunmu

+0

Podría ser como dices, en cuyo caso mi pregunta es más o menos discutible. Lógicamente, eso tendría sentido, pero la página del manual no parece ser definitiva. Además del caso de Jonathan, al final de la lectura imagino que es posible quedarse corto si está leyendo un archivo que está escribiendo otro proceso, pero quizás ese no sea un buen uso de esta técnica. – ValenceElectron

1

AFAICS las funciones de lectura/escritura con vectores funcionan de la misma WRT corto lee/escribe como los normales. Es decir, recuperas el número de bytes leídos/escritos, pero esto podría apuntar al centro de una estructura, al igual que con read()/write(). No hay garantía de que los posibles "puntos de interrupción" (a falta de un término mejor) coincidan con los límites del vector. Desafortunadamente, las funciones de IO vectorizado no ofrecen más ayuda para lidiar con lecturas cortas/escrituras que las funciones normales de IO. De hecho, es más complicado ya que necesita mapear el recuento de bytes en un elemento de vector IO y compensarlo dentro del elemento.

También tenga en cuenta que la idea de usar vectored IO para estructuras individuales o elementos de datos podría no funcionar tan bien; el valor máximo permitido para el argumento iovcnt (IOV_MAX) suele ser bastante pequeño, algo así como 1024 o más. Entonces, si sus datos son contiguos en la memoria, simplemente páselos como un solo elemento en lugar de dividirlos artificialmente.

Cuestiones relacionadas