Come ottenere un thread per continuare dopo write () ha scritto meno byte rispetto richiesto?

StackOverflow https://stackoverflow.com/questions/904422

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);
        }
    }

}
È stato utile?

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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top