我有两个程序 - 一个程序写入管道,另一个程序从管道读取。但是,当我运行它们时,错过了这些消息。
编写程序如下 -
执行时的写作过程 -
$ ./pipe.out
Write to Buffer = 0
执行时的阅读过程 -
$ ./pipe_reader.out
Pipe already exists
Read from Buffer
0
Read from Buffer
7
Read from Buffer
7
Read from Buffer
你有没有看到这里的消息丢失了?
这是程序,请解释一下这里有什么问题?如果我不这样做,同样的工作 关闭文件描述符。事实上,继续打开它。我相信这会导致其他一些问题。在这里,它起作用,因为fd打开只有10。
计划 - 班级
#include "iostream"
#include "unistd.h"
#include "stdio.h"
#include "fcntl.h"
#include "string.h"
#include <sys/stat.h>
#include <sys/types.h>
using namespace std;
class Named_Pipe
{
private:
int m_fp;
char m_name[256];
int m_rd;
int m_wr;
public:
void open_pipe(char *name);
void close_reader();
void close_writer();
void write_to_pipe(char *msg);
void read_from_pipe(char *msg);
Named_Pipe();
};
Named_Pipe::Named_Pipe()
{
/** no access to any groups and others **/
umask(077);
}
void Named_Pipe::open_pipe(char *name)
{
int rc;
struct stat pipe_exist;
strcpy(m_name,name);
if ( stat(name, &pipe_exist) == 0 )
{
cout<<"Pipe already exists"<<endl;
}
else
{
rc = mkfifo(name, S_IRWXU);
if( rc == -1)
{
cout<<strerror(rc);
}
}
}
void Named_Pipe::write_to_pipe(char *msg)
{
int rc = 0;
m_wr = open(m_name,O_WRONLY);
if( m_wr == -1)
{
cout<<"Error in opening the descriptor for writing"<<endl;
}
rc = write(m_wr,msg,256);
if( rc == -1)
cout<<"Error in writing the message"<<endl;
}
void Named_Pipe::read_from_pipe(char *msg)
{
int rc = 0;
m_rd = open(m_name,O_RDONLY);
if( m_rd == -1)
{
cout<<"Error in opening the descriptor for reading"<<endl;
}
rc = read(m_rd,msg,256);
if( rc == -1)
cout<<"Error in reading the message"<<endl;
}
void Named_Pipe:: close_reader()
{
close(m_rd);
}
void Named_Pipe:: close_writer()
{
close(m_wr);
}
现在,编写器管道进程逻辑 -
pipe.cpp
int main(int argc, char *argv[])
{
Named_Pipe write_process;
char buffer[256];
int i = 0;
write_process.open_pipe("FIRST_FIFO_PROG");
for( i= 0; i<10; i++)
{
strcpy(buffer,"MY FIRST MSG ON PIPES");
cout<<"Write to Buffer = "<< i<< endl;
sprintf(buffer,"%d",i);
write_process.write_to_pipe(buffer);
write_process.close_writer();
}
return 0;
}
现在,这里的读者管道流程。
int main(int argc, char *argv[])
{
Named_Pipe read_process;
char buffer[256];
int i = 0;
read_process.open_pipe("FIRST_FIFO_PROG");
for( i= 0; i<10; i++)
{
cout<<"Read from Buffer"<<endl;
read_process.read_from_pipe(buffer);
cout<<buffer<<endl;
read_process.close_reader();
}
return 0;
}
答案 0 :(得分:3)
您可以在读取和写入两侧保持打开和关闭FIFO。您只需打开一次,写入(并读取)您的消息,然后关闭FIFO。
你所看到的并不是一个竞争条件,而是你自己制作的计时问题。在相应的开放调用成功之前,FIFO需要读写器,而FIFO可以有多个读写器。
我看到的是以下内容的变体:
你也可以写一个固定的256字节,你可能想写strlen
字节。而且,和往常一样,阅读&amp;写一个循环。
答案 1 :(得分:1)
您的类成员函数操作与其名称不匹配。
umask()
而不执行任何其他操作。它甚至没有将文件描述符设置为已知状态。open_pipe()
函数会创建FIFO。write_to_pipe()
函数每次调用时都会打开文件并写入管道而不关闭它。read_from_pipe()
函数每次调用时都会打开文件,并从管道读取而不关闭它。close_reader()
和close_writer()
函数都会关闭文件描述符。m_fp
成员变量。尽管有一连串的问题,代码表面上应该可以工作 - 除了当所有文件描述符都关闭时FIFO会丢弃任何写入的数据。 您从comment Duck获得了此关键信息。
请注意,如果您的代码在调用close之前执行了多次读取或写入操作,那么您可能会大量泄漏资源。
这是一个重写 - 处理一些设计问题。
#ifndef PIPE_H_INCLUDED
#define PIPE_H_INCLUDED
class Named_Pipe
{
private:
char m_name[256];
int m_rd;
int m_wr;
bool m_mk; // FIFO created?
void mkpipe(char const *name);
public:
void open_reader(const char *name);
void open_writer(const char *name);
void close_reader();
void close_writer();
void write_to_pipe(const char *msg);
int read_from_pipe(char *msg, int maxlen);
Named_Pipe();
~Named_Pipe();
};
#endif // PIPE_H_INCLUDED
#include "pipe.h"
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <fcntl.h>
#include <iostream>
#include <sys/stat.h>
#include <unistd.h>
using namespace std;
Named_Pipe::Named_Pipe() : m_rd(-1), m_wr(-1), m_mk(false)
{
m_name[0] = '\0';
umask(077);
}
Named_Pipe::~Named_Pipe()
{
close_reader();
close_writer();
unlink(m_name);
}
void Named_Pipe::mkpipe(char const *name)
{
struct stat pipe_exist;
strcpy(m_name, name);
if (stat(name, &pipe_exist) != 0)
{
if (mkfifo(name, S_IRWXU) != 0)
{
cerr << strerror(errno);
exit(1);
}
}
m_mk = true;
}
void Named_Pipe::open_reader(char const *name)
{
if (!m_mk)
mkpipe(name);
m_rd = open(m_name, O_RDONLY);
if (m_rd == -1)
{
cerr << "Error in opening " << name << " for reading" << endl;
exit(1);
}
}
void Named_Pipe::open_writer(char const *name)
{
if (!m_mk)
mkpipe(name);
m_wr = open(m_name, O_WRONLY);
if (m_wr == -1)
{
cerr << "Error in opening FIFO " << name << " for writing" << endl;
exit(1);
}
}
void Named_Pipe::write_to_pipe(char const *msg)
{
if (m_wr == -1)
{
cerr << "Writing to unopened FIFO\n";
exit(1);
}
int len = strlen(msg) + 1;
if (write(m_wr, msg, len) != len)
{
cerr << "Error in writing the message" << endl;
exit(1);
}
}
int Named_Pipe::read_from_pipe(char *msg, int msglen)
{
if (m_rd == -1)
{
cerr << "Reading from unopened FIFO\n";
exit(1);
}
int rc = read(m_rd, msg, msglen - 1);
if (rc == -1)
cerr << "Error in reading the message" << endl;
else if (rc == 0)
cerr << "EOF on pipe" << endl;
else if (msg[rc-1] != '\0')
msg[rc] = '\0';
cerr << "Read " << rc << " bytes from FIFO\n";
return rc;
}
void Named_Pipe::close_reader()
{
if (m_rd != -1)
{
close(m_rd);
m_rd = -1;
}
}
void Named_Pipe::close_writer()
{
if (m_wr != -1)
{
close(m_wr);
m_wr = -1;
}
}
#include "pipe.h"
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
Named_Pipe read_process;
char buffer[256];
int i = 0;
read_process.open_reader("FIRST_FIFO_PROG");
for (i = 0; i < 10; i++)
{
int nbytes = read_process.read_from_pipe(buffer, sizeof(buffer));
const char *data = buffer;
int counter = 0;
while (nbytes > 0)
{
int len = strlen(data);
cout << "Reader" << counter << ": [" << data << "]" << endl;
nbytes -= len + 1;
data += len + 1;
}
}
read_process.close_reader();
cout << "Reader complete\n";
return 0;
}
#include "pipe.h"
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
Named_Pipe write_process;
char buffer[256];
write_process.open_writer("FIRST_FIFO_PROG");
for (int i = 0; i < 10; i++)
{
sprintf(buffer, "Message on FIFO %d", i);
cout << "Write to Buffer = [" << buffer << "]" << endl;
write_process.write_to_pipe(buffer);
}
write_process.close_writer();
cout << "Writer complete\n";
return 0;
}
示例1:
$ pipe-writer & sleep 1 ; pipe-reader
[1] 9576
Write to Buffer = [Message on FIFO 0]
Write to Buffer = [Message on FIFO 1]
Write to Buffer = [Message on FIFO 2]
Write to Buffer = [Message on FIFO 3]
Write to Buffer = [Message on FIFO 4]
Write to Buffer = [Message on FIFO 5]
Write to Buffer = [Message on FIFO 6]
Write to Buffer = [Message on FIFO 7]
Write to Buffer = [Message on FIFO 8]
Write to Buffer = [Message on FIFO 9]
Writer complete
Read 180 bytes from FIFO
Reader0: [Message on FIFO 0]
Reader1: [Message on FIFO 1]
Reader2: [Message on FIFO 2]
Reader3: [Message on FIFO 3]
Reader4: [Message on FIFO 4]
Reader5: [Message on FIFO 5]
Reader6: [Message on FIFO 6]
Reader7: [Message on FIFO 7]
Reader8: [Message on FIFO 8]
Reader9: [Message on FIFO 9]
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
Reader complete
[1]+ Done pipe-writer
$
示例2:
$ pipe-writer & pipe-reader
[1] 9579
Write to Buffer = [Message on FIFO 0]
Write to Buffer = [Message on FIFO 1]
Write to Buffer = [Message on FIFO 2]
Write to Buffer = [Message on FIFO 3]
Write to Buffer = [Message on FIFO 4]
Write to Buffer = [Message on FIFO 5]
Read Write to Buffer = [Message on FIFO 6]
Write to Buffer = [Message on FIFO 7]
Write to Buffer = [Message on FIFO 8]
Write to Buffer = [Message on FIFO 9]
36Writer complete
bytes from FIFO
Reader0: [Message on FIFO 0]
Reader1: [Message on FIFO 1]
Read 144 bytes from FIFO
Reader0: [Message on FIFO 2]
Reader1: [Message on FIFO 3]
Reader2: [Message on FIFO 4]
Reader3: [Message on FIFO 5]
Reader4: [Message on FIFO 6]
Reader5: [Message on FIFO 7]
Reader6: [Message on FIFO 8]
Reader7: [Message on FIFO 9]
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
EOF on pipe
Read 0 bytes from FIFO
Reader complete
[1]+ Done pipe-writer
$
现在你可以看到为什么读者主程序中有额外的循环。
我仍然不认为这是一个好的设计。类中应该只有一个文件描述符。应将FIFO的名称传递给构造函数,并指示这是用于读取还是写入。 FIFO的名称在两个程序中复制;应该使用通用名称。我保留了close_xxxxer()
函数,但最好让析构函数完成这项工作。您可以将函数名称简化为read()
和write()
。代码错误检查但写入cerr
(不是cout
)并在出错时退出。请注意,返回代码-1与从errno
获得的错误号不同。
答案 2 :(得分:0)
#include "iostream"
#include "unistd.h"
#include "stdio.h"
#include "fcntl.h"
#include "string.h"
#include <sys/stat.h>
#include <sys/types.h>
using namespace std;
class Named_Pipe
{
private:
int m_fp;
char m_name[256];
int m_rd;
int m_wr;
public:
void open_pipe(char *name);
void close_reader();
void close_writer();
void write_to_pipe(char *msg);
void read_from_pipe(char *msg);
Named_Pipe(int read_desc, int write_desc);
~Named_Pipe();
};
Named_Pipe::Named_Pipe(int read_desc, int write_desc):m_rd(read_desc), m_wr(write_desc)
{
/** no access to any groups and others **/
umask(077);
}
Named_Pipe::~Named_Pipe()
{
/** This is to remove the pipe create **/
unlink(m_name);
}
void Named_Pipe::open_pipe(char *name)
{
int rc;
struct stat pipe_exist;
strcpy(m_name,name);
if ( stat(name, &pipe_exist) == 0 )
{
cout<<"Pipe already exists"<<endl;
}
else
{
rc = mkfifo(name, S_IRWXU);
if( rc == -1)
{
cout<<strerror(rc);
}
}
}
void Named_Pipe::write_to_pipe(char *msg)
{
int rc = 0;
if ( m_wr == -1)
{
m_wr = open(m_name,O_WRONLY);
if( m_wr == -1)
{
cout<<"Error in opening the descriptor for writing"<<endl;
}
}
rc = write(m_wr,msg,256);
if( rc == -1)
cout<<"Error in writing the message"<<endl;
}
void Named_Pipe::read_from_pipe(char *msg)
{
int rc = 0;
if( m_rd != 0)
{
m_rd = open(m_name,O_RDONLY);
if( m_rd == -1)
{
cout<<"Error in opening the descriptor for reading"<<endl;
}
}
rc = read(m_rd,msg,256);
if( rc == -1)
cout<<"Error in reading the message"<<endl;
}
void Named_Pipe:: close_reader()
{
close(m_rd);
}
void Named_Pipe:: close_writer()
{
close(m_wr);
}
现在,作家和读者分别处理。
int main(int argc, char *argv[])
{
/* reader and writer , -1 un-initialized and 0 means intialized **/
Named_Pipe write_process(0,-1);
char buffer[256];
int i = 0;
write_process.open_pipe("FIRST_FIFO_PROG");
for( i= 0; i<10; i++)
{
sprintf(buffer,"%s %d","MY FIRST MSG ON PIPES",i);
cout<<"Write Buffer = "<< buffer<< endl;
write_process.write_to_pipe(buffer);
}
write_process.close_writer();
return 0;
}
读者流程 -
int main(int argc, char *argv[])
{
/* reader and writer , -1 un-initialized and 0 means intialized **/
Named_Pipe read_process(-1,0);
char buffer[256];
int i = 0;
read_process.open_pipe("FIRST_FIFO_PROG");
for( i= 0; i<10; i++)
{
read_process.read_from_pipe(buffer);
cout<<"Read Buffer = "<< buffer<< endl;
}
read_process.close_reader();
return 0;
}