这是我的简单代码,用于打开命名管道,将字符串写入其中,然后关闭管道。管道是在另一个功能中创建的,如下所述。
char * ipcnm = "./jobqueue";
std::cout << "opening job queue" << std::endl;
//ensure the jobqueue is opened
if ((jobq = open(ipcnm, O_WRONLY)) < 0) {
perror("open");
exit(-1);
}
std::cout << "queue opened" << std::endl;
// record the number of bytes written to the queue
size_t written = write(jobq, ptr, size*nmemb);
// close fifo
if (close(jobq) < 0) {
perror("close");
exit(-1);
}
// need to report to other agents the size of the job that was written
jobSizes.push_back(written);
但是对open()的调用挂起。我确保在调用时没有其他进程使用fifo“jobqueue”,并且创建队列后的队列文件权限设置为prwxrwxr-x(我只是使用mkfifo(ipcnm, 0777)
来创建管道。
我一开始认为组o
在此管道上缺少w
权限是一个问题,所以我用chmod手动更改了它们,它仍然挂起,因为“队列打开”从不得到印刷。 perror的错误消息也没有(“打开”);
我错过了什么?
答案 0 :(得分:12)
当您打开FIFO进行写入时,编写器将被阻止,直到有读取器为止。
你可能错过了读者。
您无法写入管道,然后关闭它,然后让读者稍后出现。这种存储语义是通过使用常规文件来完成的。
管道是一种进程间通信机制;通过打开FIFO创建的管道类似于pipe
POSIX C库函数返回的对象,除了pipe
返回已经为I / O准备的对象,因为有两个描述符:对端开启I / O的相反方向。而FIFO的端点是一次一个地单独打开的。
文件系统中的FIFO对象只是一个允许多个进程连接到同一个管道的接触点。
最初,不存在管道对象。当第一个进程在文件系统中的FIFO对象上执行open
时,将创建一个管道。来自同一进程的任何其他open
请求或另一个请求附加到内核中保存的同一管道对象。在管道至少打开一次以进行读取之前不能进行I / O,至少一次用于写入。实际的管道I / O通过内核;它不存储在文件系统中。当所有进程关闭管道时,对象就会消失。
可以设计FIFO,使得I / O可以在任何进程打开对象以进行读取之前开始。也就是说,可以允许写入请求继续,然后仅在管道填满时阻止。那个设计会有问题。例如,如果写入很小,管道不会填满怎么办?编写器将编写数据并继续执行。如果它只是在读者读取数据之前退出,数据就会永远消失!阻塞行为确保读者可以捕获数据;当编写器被解锁时,可以确定读取器已打开管道,因此它可以安全地关闭管道末端而不会丢失数据。即使没有可用的读取器,也不会阻止写入的设计必须将管道对象保持在内核内部,即使没有进程打开它,这样作者可以打开管道,将数据放入其中,然后离开,后来读者可以拿起数据。否则,设计必须向编写者提供阻塞close
(类似于SO_LINGER
- 在套接字上安排的行为),等待先前写入的数据被删除。
答案 1 :(得分:2)
使用O_RDWR代替O_WRONLY进行打开。这将打开fifo而不会阻塞,即使读者没有打开另一端。