Come ottenere un thread per continuare dopo write () ha scritto meno byte rispetto richiesto?
-
05-09-2019 - |
Domanda
Sto utilizzando il seguente codice per scrivere i dati tramite una named pipe da un'applicazione all'altra. Il thread in cui la scrittura è avvenuta non dovrebbe mai essere uscito. Ma se r_write () restituisce meno di quanto dovrebbe, il filo / programma si arresta per qualche ragione. Come posso fare il filo continuare una volta scrittura è tornato meno di quanto dovrebbe?
ssize_t r_write(int fd, char *buf, size_t size)
{
char *bufp;
size_t bytestowrite;
ssize_t byteswritten;
size_t totalbytes;
for (bufp = buf, bytestowrite = size, totalbytes = 0;
bytestowrite > 0;
bufp += byteswritten, bytestowrite -= byteswritten) {
byteswritten = write(fd, bufp, bytestowrite);
if ((byteswritten) == -1 && (errno != EINTR))
return -1;
if (byteswritten == -1)
byteswritten = 0;
totalbytes += byteswritten;
}
return totalbytes;
}
void* sendData(void *thread_arg)
{
int fd, ret_val, count, numread;
string word;
char bufpipe[5];
ret_val = mkfifo(pipe, 0777); //make the sprout pipe
if (( ret_val == -1) && (errno != EEXIST))
{
perror("Error creating named pipe");
exit(1);
}
while(1)
{
if(!sproutFeed.empty())
{
string s;
s.clear();
s = sproutFeed.front();
int sizeOfData = s.length();
snprintf(bufpipe, 5, "%04d", sizeOfData);
char stringToSend[strlen(bufpipe) + sizeOfData +1];
bzero(stringToSend, sizeof(stringToSend));
strncpy(stringToSend,bufpipe, strlen(bufpipe));
strncat(stringToSend,s.c_str(),strlen(s.c_str()));
strncat(stringToSend, "\0", strlen("\0"));
int fullSize = strlen(stringToSend);
cout << "sending string" << stringToSend << endl;
fd = open(pipe,O_WRONLY);
int numWrite = r_write(fd, stringToSend, strlen(stringToSend) );
if(numWrite != fullSize)
{
bzero(bufpipe, strlen(bufpipe));
bzero(stringToSend, strlen(stringToSend));
cout << "NOT FULL SIZE WRITE " << endl; //program ends here??
}
else
{
sproutFeed.pop();
bzero(bufpipe, strlen(bufpipe));
bzero(stringToSend, strlen(stringToSend));
}
}
else
{
sleep(1);
}
}
}
Soluzione
La scrittura per il FIFO non è riuscito. Indagare il valore di errno
per scoprire perché. Guardate in errno.h
sul sistema per decifrare il valore di errno. Se il programma sta per finire su cercando di scrivere alla console, il motivo può essere correlato.
Inoltre, il ciclo non sembra essere la chiusura del descrittore di file per il FIFO (close(fd)
).
Infine, si parla multithreading. Lo standard flusso libreria cout
sul vostro sistema non può (e probabilmente non è) thread-safe. In tal caso, scrivere sulla console contemporaneamente da più thread causerà errori imprevedibili.
Altri suggerimenti
Se il write()
restituisce un valore positivo (diverso da zero, non negativo) per il numero di byte scritti, ha avuto successo, ma non c'era spazio per tutti i dati. Riprovare, scrivendo il resto dei dati dal buffer (e ripetere se necessario). Da non dimenticare, una FIFO ha una capacità limitata - e scrittori si terrà, se necessario
Se il write()
restituisce un valore negativo, non è riuscito la scrittura. Le probabilità sono che non sarà in grado di recuperare, ma controllare errno
per il motivo per cui.
Credo che l'unica circostanza in cui write()
può restituire zero è se avete il file descrittore aperto con O_NONBLOCK
e il tentativo di scrivere potrebbe bloccare. Potrebbe essere necessario controllare la pagina di manuale per write()
per verificare la presenza di eventuali altre possibilità.
Che cosa il vostro filetto fa poi dipende perché ha vissuto una breve scrittura, e che cosa si vuole fare.
Hai bisogno di fare il descrittore di file non bloccante. Si può fare in questo modo:
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
Spiegazione
Questo è come funziona fcntl
(non una descrizione completa - guardano man fcntl
per questo). Prima di tutto, la comprende:
#include <unistd.h>
#include <fcntl.h>
leggere le bandiere del descrittore di file
Usa F_GETFL
per ottenere le bandiere del descrittore di file. Da man fcntl
:
F_GETFL Read the file descriptor's flags. RETURN VALUE For a successful call, the return value depends on the operation: F_GETFL Value of flags.
e questo è come viene utilizzato:
int fd_flags = fcntl(fd, F_GETFL);
scrittura bandiere del descrittore di file
Usa F_SETFL
per impostare il flag O_NONBLOCK
. Anche in questo caso, citando man fcntl
:
F_SETFL Set the file status flags part of the descriptor's flags to the value specified by arg. Remaining bits (access mode, file cre? ation flags) in arg are ignored. On Linux this command can only change the O_APPEND, O_NONBLOCK, O_ASYNC, and O_DIRECT flags.
e questo è come viene utilizzato:
fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);