Você está na página 1de 7

ElbufferdelaentradaestndarenGNU/Linux

MatasZabaljuregui(matiasz@info.unlp.edu.ar) http://linux.linti.unlp.edu.ar

0. Introduccin Seintentardescribirentrminossencilloslaformadetratarlosdatosingresadosporel usuarioatravsdelaentradaestndardeunprocesoexplicandobrevementeel funcionamientodelosbuffersdelosstreamestndardeentrada/salida. Partedelainformacinseobtienedelmanualdelalibreraglibc,cuyalecturase recomiendaypuedeencontrarseen: :// http www.gnu.org /software/ /manual/ libc

1. StreamsEntrada/Salida Unstreamesunaabstraccindealtonivelquerepresentauncanaldecomunicacin haciaodesdeunarchivo,undispositivoounproceso.Esteconceptoseimplementaa travsdepunterosaestructurasdetipoFILEdeclaradasenelarchivostdio.h. Cuandounprocesocomienzasuejecucin,elsistemaoperativoabretresstreams:stdin (standardinput),stdout(standardoutput)ystderr(standarderror).Generalmenteel primeroseasociaaltecladoylosotrosdosalmonitor.stopuedemodificarseal momentodeinvocarelprocesoutilizandolasfacilidadesderedireccinypipesdelshell deLinux.

2. Buffers Loscaracteresqueescribimosenunstream,normalmentesevanacumulandoenun buffer(espaciodememoria)parasertransmitidosasincrnicamentehaciaeldispositivoo archivo.Porejemplo,siestamosescribiendoenunarchivodetexto,cadavezque enviamosuncarcteralstream,esteesalmacenadotemporalmenteenunbufferen espaciodeusuario,hastaqueporalgnevento(bufferlleno,carcterdefindelnea, funcindelimpiadodebuffers,etc)seinvocaalallamadaalsistemaqueenvalosdatos aldisco[1].


[1]Enrealidad,losdatospasarnportodaunajerarquadebuffers antesdeserescritoseneldispositivo.EstosbuffersseimplementanenlossubsistemasdePageCache, VirtualFileSystem(VFS)yeldriverdeldispositivodealmacenamiento,todosincluidosenelkernelLinux.

Delmismomodo,cuandoingresamoscaracteresdeltecladouotrodispositivodeentrada, normalmenteestossevanacumulandoenunbufferenespaciodeusuario(previo bufferingenespaciodelkernelaunquehayalgunasexcepcionesaesto).Cuandose llamaaunafuncindelecturasobrestdin,enrealidadestamosleyendoelcontenidode estebuffer,comoseobservaenelsiguientediagrama:

fgets(miBuffer,15,stdin) ^ ^ bufferdestdin ^ ^

(espaciodeusuario)

(espaciodeusuario)

driver/subsistemaTTY (kernel) ^ ^ dispositivodeentrada (hardware)

3. EstrategiasdeBuffering Existentresestrategiasdiferentesdebuffering:

UnbefferedStream :Loscaracteresescritosoledosdesdeelstreamsontransmitidos individualmentehaciaodesdeeldispositivo/archivotanprontocomoseaposible. LineBufferedStream :Loscaracteresescritosalstreamsontransmitidosenbloquesal archivorecincuandoseescribeuncarcternewline('\n'). FullyBufferedStream:Loscaracteresescritosoledosdesdeelstreamson transmitidoshaciaodesdeeldispositivo/archivoenbloquesdetamaoarbitrario.

Alcrearunstream,stenormalmenteutilizaunaestrategiaFullyBuffered.Sinembargo existeunaexcepcinimportante:losstreamdesalidaasociadosaundispositivo interactivocomounaterminal,loscualesrespondenaunaestrategiaLineBuffered.Esto implicaquelosmensajesdesalidaqueterminenconelcarcternewlinedeberan aparecerinmediatamenteenpantalla.

Alprincipioesteprocesosueleresultaruntantoengorrosoporelhechodequeen realidadseestrealizandounaoperacintansimplecomoporejemplolalecturade caracteresdelteclado.Sinembargodeberatenerseencuentaquelainterfazofrecida porlosstreamsnospermiteelaccesoatodotipodehardware[2]ylaposibilidadde optimizarelmecanismodebufferingsubyacentepuedeimplicarmejorasimportantesdela performance.

[2]SesueledecirqueenlafamiliadesistemasoperativostipoUnixtodoesunarchivo.Porejemplo,el cdigoparaenviarunaseriedecaracteresaunarchivodetexto,alpuertoserieoalmonitoreselmismo.

4. FlushyPurge Hacerunflushdelasalidaenelbufferdeunstreamsignificatransmitiral archivo/dispositivotodosloscaracteresacumuladosenelbuffer.Existenvarioseventos quedisparanunaoperacindeflushautomticamente,perocuandonecesitamos invocarlaexplcitamente,seutilizalafuncinfflushdeclaradaenstdio.h:

intfflush(FILE*stream) Thisfunctioncausesanybufferedoutputonstreamtobedeliveredtothefile.Ifstream isanullpointer,thenfflushcausesbufferedoutputonallopenoutputstreamstobe flushed. ThisfunctionreturnsEOFifawriteerroroccurs,orzerootherwise.

Enalgunassituacionesdondelainformacinenelbuffernoestilysimplementese puededesecharesposibleutilizarunafuncinquefueintroducidaenSolarisyquesi bienNOesestndar,seincluyeenlalibreraglibc.Notarqueesnecesarioincluirel archivostdio_ext.h,encuyocasoyanosernecesarioincluirstdio.h. void__fpurge(FILE*stream) The__fpurgefunctioncausesthebufferofthestreamstreamtobeemptied.Ifthe streamiscurrentlyinreadmodeallinputinthebufferislost.Ifthestreamisinoutput 3

modethebufferedoutputisnotwrittentothedevice(orwhateverotherunderlying storage)andthebufferthecleared. Thisfunctionisdeclaredinstdio_ext.h. 5.Ejemplosdecmolimpiarelbufferdeteclado Ejecutandoelsiguientecdigo:

#include<stdio.h> intmain() { charnombre[50]; printf("Nombre:"); scanf("%s",nombre); printf("%s",nombre); printf("newline\n"); return0; }

Sepuedeobservarquescanfdejaelcarcternewlineenelbufferdestdinenlugarde copiarloanombre.Esteesunodeloscasosenqueenlasprximasllamadasascanf(u otrafuncin)tendremoscomportamientosextraos.Peronotodaslasfuncionesde lecturasecomportanigual,porejemplo:

#include<stdio.h> intmain() { charnombre[50]; printf("Nombre:"); fgets(nombre,sizeof(nombre),stdin); printf("%s",nombre); printf("newline\n");

return0; }

Estecdigodemuestraquefgetsnodejaelcarcternewlineenelbufferdestdin,en cambiolocopiaanombre.Sinembargo,siingresamosportecladounstringdelongitud mayoroiguala50tendremosproblemassiluegoleemosnuevamentedestdinyaque fgetsleecaracteresdelbufferhastaunomenosquelacantidadindicadaensusegundo argumento(enestecasolee49yenlaltimaposicincolocaelcarcter'\0',ofinde string).

Porejemplo,sisecompilaelsiguientecdigo

#include<stdio.h> intmain() { charnombre[5]; printf("Nombre:"); fgets(nombre,sizeof(nombre),stdin); printf("%s",nombre); printf("newline\n"); fgets(nombre,sizeof(nombre),stdin); printf("%s",nombre); printf("newline\n"); return0; }

yseingresaunstringde10caracteresenlaprimeroportunidadquenosdaelprograma, elsegundofgetstomaelremanentedejadoenelbufferporelprimerfgets.

Acontinuacinsepresentandosejemplosdecmosepuedelimpiarelbufferdelstream 5

stdinenGNU/Linux.Esimportanterecordarquefflush()noestdefinidaparastdin,sino parabuffersdesalidacomoeldestdout.

Enelprimerejemploseutilizaunloopparaterminardeleercaracteresquepueden haberquedadoenelbufferporingresospreviosdecaracteres.Esteeselcdigo

#include<stdio.h> intmain() { charnombre[5]; printf("Nombre:"); fgets(nombre,sizeof(nombre),stdin); printf("%s",nombre); printf("newline\n"); printf("Apellido:"); while(getchar()!='\n');/*LEEDELBUFFERHASTAQUEENCUENTRA fgets(nombre,sizeof(nombre),stdin);UNCARACTERNEWLINE*/ printf("%s",nombre); printf("newline\n"); return0; }

Esposibledefinirunamacroqueimplementeelloop,comosehaceacontinuacin: #defineFLUSHwhile(getchar()!='\n')

Elsegundoejemploutilizalafuncin__fpurge()explicadaenelpunto4.Debe destacarseque__fpurgenoesestandaryquesilaportabilidaddelcdigoqueestamos generandoesunfactorimportante,sedeberautilizarlasolucinanterior,sinembargo estecdigofuncionasinproblemasenGNU/Linux(asicomoenotrasvariantesdeUnix). 6

#include<stdio_ext.h> { charnombre[5]; printf("Nombre:"); fgets(nombre,sizeof(nombre),stdin); printf("%s",nombre); printf("newline\n"); printf("Apellido:"); __fpurge(stdin);/*BORRAELCONTENIDODELBUFFERDESTDIN*/ fgets(nombre,sizeof(nombre),stdin); printf("%s",nombre); printf("newline\n"); return0; }

Você também pode gostar