Non-blocking mode is inderdaad een goede optie. Ik vind het zelf erg jammer dat je dan nog geen timeout kunt specificeren; je zult dus zelf iets met timing en polling moeten doen. Simpelweg code als deze gebruiken werkt niet goed:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
| char buffer[1024];
int size;
FILE *fp = popen("bc", "r+");
fcntl(fp, F_SETFL, O_NONBLOCK);
fwrite(fp, "666*666+666\n");
fflush(fp);
size = fread(buffer, 1, sizeof(buffer), fp);
if(size < 0)
...; /* report error */
if(size == 0)
...; /* no data available */
else
...; /* buffer contains 'size' bytes */ |
Hoewel dat in de praktijk waarschijnlijk nog 'vaak' goed zou kunnen gaan. In een multiprogrammed omgeving is er echt geen enkele garantie dat de applicatie die je aanroept het resultaat beschikbaar heeft, direct nadat jij je uitvoer naar het proces toe hebt geflushed. Met blocked I/O hoef je je daar geen zorgen over te maken.
Het gebruik van select ligt dan, wat mij betreft, meer voor de hand; dan kun je tenminste een zinnige timeout specificeren, alvorens je concludeert dat de gegevens niet beschikbaar zijn. Timing laat je dan aan de implementatie van select over. Zo iets dus:
C:
1
2
3
4
5
6
7
8
9
10
11
12
| fd_set fds;
int result;
FD_ZERO(&fds);
FD_SET(fileno(fp), &fds);
timeval to = { 0, 500000 }; /* 500 ms */
result = select(&fds, NULL, NULL, &to);
if(result == 0)
... ; /* timeout expired */
else if (result ==1)
.... ; /* fp readable */
else
.... ; /* report error */ |
Als je dan toch je timeout instelt op een redelijke waarde (die je maximaal accepteert om op een antwoord te wachten) dan heb je eigenlijk die non-blocking mode eigenlijk niet meer nodig; je leest de file descriptor toch uitsluitend uit als er gegevens beschikbaar zijn.
Je lost hiermee trouwens nog niet het probleem op dat het goed mogelijk is dat als er veel uitvoer is, je slechts een deel gelezen hebt (en niet, bijvoorbeeld, precies een hele regel). Je zou dat wel met fgets() ofzo kunnen doen, maar dan heb je weer het probleem dat zo'n functie in non-blocking mode er ook halverwege mee kan stoppen (dacht ik?) waardoor je weer terug bij af bent...
Voor het probleem van de TS is het misschien nog wel het makkelijkst om een aparte thread te spawnen voor de I/O (dan blijft de GUI ook gewoon responsief), die de uitvoer regel voor regel beschikbaar maakt en gewoon blocking I/O gebruikt. Maar goed, dat maakt het niet minder interessant om de voor- en nadelen van non-blocking I/O eens te bespreken.
Code is niet getest; er zouden hier en daar wat foutjes in kunnen zitten.
[
Voor 21% gewijzigd door
Soultaker op 01-10-2003 10:16
]