1

次のコードを使用して、あるアプリケーションから別のアプリケーションに名前付きパイプを介してデータを書き込みます。書き込みが行われるスレッドは、決して終了してはなりません。しかし、r_write() の戻り値が本来よりも少ない場合、スレッド/プログラムは何らかの理由で停止します。write が本来よりも少ない値を返したら、スレッドを継続させるにはどうすればよいですか?

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

}
4

3 に答える 3

3

write()が書き込まれたバイト数に対して正の (ゼロでも負でもない) 値を返す場合は、成功ですが、すべてのデータを格納する余地がありませんでした。バッファから残りのデータを書き込んで再試行します (必要に応じて繰り返します)。FIFO の容量には制限があることを忘れないでください。また、必要に応じてライターが停止します。

write()が負の値を返す場合、書き込みは失敗しました。回復できない可能性がありますがerrno、その理由を確認してください。

write()ゼロを返すことができる唯一の状況は、ファイル記述子を開いているO_NONBLOCKときに書き込みの試行がブロックされる場合だと思います。write()のマニュアルページを精査して、他の可能性を確認する必要がある場合があります。

その後のスレッドの動作は、短い書き込みが発生した理由と、それに対して何をしたいかによって異なります。

于 2009-05-24T20:00:14.647 に答える
1

FIFO への書き込みに失敗しました。の値errnoを調べて理由を見つけます。errno.hシステムを調べて、errno の値を解読してください。コンソールに書き込もうとしてプログラムが終了している場合は、その理由が関連している可能性があります。

また、ループが FIFO ( ) のファイル記述子を閉じているようには見えませんclose(fd)

最後に、マルチスレッドについて言及します。システムの標準ライブラリ ストリームcoutは、スレッドセーフではない可能性があります (おそらくそうではありません)。その場合、複数のスレッドから同時にコンソールに書き込むと、予期しないエラーが発生します。

于 2009-05-24T19:35:21.797 に答える
0

ファイル記述子をノンブロッキングにする必要があります。次のように実行できます。

fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

説明

これがどのように機能するかですfcntl(完全な説明ではありません-それについては見てくださいman fcntl)。まず第一に、含まれるもの:

#include <unistd.h>
#include <fcntl.h>

ファイル記述子のフラグを読み取る

F_GETFLファイル記述子のフラグを取得するために使用します。からman fcntl:

       F_GETFL
              ファイル記述子のフラグを読み取ります。

戻り値
       呼び出しが成功した場合、戻り値は操作によって異なります。

       F_GETFL フラグの値。

そして、これはそれがどのように使用されるかです:

int fd_flags = fcntl(fd, F_GETFL);

ファイル記述子のフラグの書き込み

フラグF_SETFLを設定するために使用します。O_NONBLOCK繰り返しますが、から引用しman fcntlます:

       F_SETFL
              記述子のフラグのファイル ステータス フラグ部分を
              arg で指定された値。残りのビット (アクセスモード、ファイル cre?
              arg のフラグ) は無視されます。Linux では、このコマンドは
              O_APPEND、O_NONBLOCK、O_ASYNC、および O_DIRECT のみを変更します
              フラグ。

そして、これはそれがどのように使用されるかです:

fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
于 2009-05-24T19:59:27.503 に答える