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 回答