我正在使用内核2.6在Linux上编写一个网络守护程序,它有 一个生产者进程和N个消费者进程,它们不会对数据进行任何更改,也不会向生产者创建任何响应.
每当生产者进程生成一个数据对象,其长度从几个10字节变化到几十个K字节时,就必须将数据对象传递给一个可用的消费者进程.
第一次,我考虑使用命名/未命名的PIPE.但是,它们将是内存复制开销.
由于该程序可能与大量具有低延迟的对等端一起工作,因此复制开销可能是有害的.因此,我决定使用POSIX共享内存和mmap().
我只是想知道使用POSIX共享内存和mmap()的进程之间的共享数据是否不会导致任何内存复制,这与PIPE不同.
此外,还有其他方法可以在进程之间共享数据,但结果是零拷贝吗?该程序将在具有最新版本内核的Linux上运行,并且可能不具备跨平台能力.
我决定不为每个消费者/产品生成/运行一个线程,而是由于设计问题而产生一个过程.
谢谢你的答复.
阅读这篇零拷贝文章,
Windows操作系统(服务器2003,2008,2008 R2)中是否存在零拷贝?
在Java中我会使用java.nio库并使用FileChannel.transferTo()和FileChannel.transferFrom().在(特定)C#中是否有类似的东西或我是否必须从某个地方加载一些未管理的.dll?谷歌在这种情况下并没有用处.
编辑:我应该注意到我的目标是.NET 3.5.
这是关于splice()的另一个问题.我希望用它来复制文件,我试图使用两个拼接调用,通过像splice维基百科页面上的例子一样的管道连接.我写了一个简单的测试用例,它只试图从一个文件读取前32K字节并将它们写入另一个文件:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv) {
int pipefd[2];
int result;
FILE *in_file;
FILE *out_file;
result = pipe(pipefd);
in_file = fopen(argv[1], "rb");
out_file = fopen(argv[2], "wb");
result = splice(fileno(in_file), 0, pipefd[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
printf("%d\n", result);
result = splice(pipefd[0], NULL, fileno(out_file), 0, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);
printf("%d\n", result);
if (result == -1)
printf("%d - %s\n", errno, strerror(errno));
close(pipefd[0]);
close(pipefd[1]);
fclose(in_file);
fclose(out_file);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,输入文件似乎正确读取,但第二次拼接调用失败了EINVAL.谁知道我在这里做错了什么?
谢谢!
我想将UDP数据包直接从以太网适配器复制到我的用户空间缓冲区
我的设置的一些细节:
我从一对千兆以太网摄像头接收数据.合并我每秒接收28800个UDP数据包(每行1个数据包*30FPS*2个摄像头*480行).有没有办法对我来说,切换到巨型帧,并且我已经寻找到调整驱动级中断,可降低CPU使用率.我在这里所说的是减少复制这个~40MB/s数据流的次数.
这是我在此发现的最佳来源,但我希望有更完整的参考或证明这种方法在实践中得到解决.
我正在阅读如何使用java nio库来利用O/S级别的文件传输/缓冲,这称为"零复制".
那么你创建/写入文件的方式有何不同?使用零拷贝有什么缺点吗?
我有多个线程需要使用TCP流中的数据.我希望在共享内存中使用循环缓冲区/队列来从TCP套接字读取.TCP接收将直接写入循环队列.消费者将从队列中读取.
此设计应启用零复制和零锁定.但是这里有两个不同的问题.
从TCP套接字读取1条逻辑消息是否可能/有效?如果没有,并且我阅读了多条消息,我将不得不将残差复制到此 - >下一步.
是否真的可以实现无锁队列?我知道有原子操作,但这些也很昂贵.因为所有CPU缓存都需要无效.这将影响我所有24个内核的所有操作.
我在低级TCP中有点生疏,并不清楚如何判断消息何时完成.我是在寻找\ 0还是具体实现?
TY
我想在映射内存上使用零拷贝cudaHostGetDevicePointer.我可以使用thrust::host_vector或者必须使用cudaHostAlloc(...,cudaHostAllocMapped)?
或者它是否更容易使用Thrust?
是否有一种可移植的方法可以丢弃来自套接字的许多传入字节而不将它们复制到用户空间?在常规文件上,我可以使用lseek(),但在套接字上,这是不可能的。我有两种可能需要它的场景:
记录流到达文件描述符(可以是 TCP、SOCK_STREAM 类型 UNIX 域套接字或可能是管道)。每个记录前面都有一个固定大小的标头,指定其类型和长度,后面是可变长度的数据。我想先读取标头,如果它不是我感兴趣的类型,我想丢弃以下数据段,而不将它们传输到用户空间到虚拟缓冲区中。
长度可变且不可预测的记录流到达文件描述符。由于异步性质,当 fd 变得可读时,记录可能仍然不完整,或者当我尝试将固定数量的字节读入缓冲区时,它们可能是完整的,但下一条记录的一部分可能已经存在。我想停止在记录之间的确切边界处读取文件描述符,这样我就不需要管理我不小心从文件描述符中读取的部分加载的记录。因此,我使用recv()withMSG_PEEK标志读入缓冲区,解析记录以确定其完整性和长度,然后再次正确读取(从而实际上从套接字中删除数据)到准确的长度。这将复制数据两次 - 我想通过简单地丢弃套接字中缓冲的确切数量的数据来避免这种情况。
在 Linux 上,我认为可以通过使用splice()数据并将其重定向到/dev/null而不将它们复制到用户空间来实现这一点。但是,splice()仅适用于 Linux,并且sendfile()更多平台上支持的类似功能不能使用套接字作为输入。我的问题是:
有没有一种可移植的方法来实现这一目标?是否也可以在其他没有 UNIX(主要是 Solaris)的 UNIX 上运行splice()?
splice()-ing是/dev/null在 Linux 上执行此操作的有效方法,还是浪费精力?
理想情况下,我希望有一个简单地从内核中的文件描述符fdssize_t discard(int fd, size_t count)中删除可读字节数(即不将任何内容复制到用户空间),阻塞可阻止的 fd 直到丢弃请求的字节数,或者返回成功的数量就像在非阻塞 fd 上丢弃字节或 EAGAIN 一样。当然,并在常规文件上推进查找位置:)read()