c - 使用 Linux AIO,能够执行 IO,但也会将垃圾写入文件

标签 c linux pointers io aio

这可能看起来很愚蠢,但是,我使用的是 libaio(不是 posix aio),我可以向文件中写入一些内容,但我也会向文件中写入额外的内容。

我看了iocb的对齐要求和buffer字段的数据类型。

这里是代码示例(仅使用相关部分,用于表示)

aio_context_t someContext;
struct iocb somecb;
struct io_event someevents[1];
struct iocb *somecbs[1];
somefd = open("/tmp/someFile", O_RDWR | O_CREAT);
char someBuffer[4096];

... // error checks 
someContext = 0; // this is necessary 
io_setup(32, &someContext ); // no error checks pasted here
strcpy(someBuffer, "hello stack overflow"); 


memset(&somecb, 0, sizeof(somecb));
somecb.aio_fildes = somefd ;
somecb.aio_lio_opcode = IOCB_CMD_PWRITE;
somecb.aio_buf = (uint64_t)someBuffer;
somecb.aio_offset = 0;
somecb.aio_nbytes = 100; // // // 
// I am avoiding the memeaign and sysconf get page part in sample paste
somecbs[0] = &somecb;  // address of the solid struct, avoiding heap
// avoiding error checks for this sample listing 
io_submit(someContext, 1, somecbs); 
// not checking for events count or errors 
io_getevents(someContext, 1, 1, someevents, NULL);

输出:

这段代码确实创建了文件,并写入了预期的字符串 你好堆栈溢出到文件/tmp/someFile。

问题:

文件/tmp/someFile 还在预期的字符串之后依次包含, @^@^@^@^@^@^@^@^@^ 和文件本身的一些部分(代码部分),可以说是垃圾。

我在某种程度上确定这是数据字段中的某个指针出错了,但无法破解。

  • 如何使用 aio(而非 posix)将“hello world”准确且仅写入文件?

我知道到目前为止,所有文件系统可能都不支持 aio 调用。我反对的人确实支持。

编辑 - 如果您想要这次尝试的入门包,您可以从这里获得。

http://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt

编辑 2:粗心大意,我在文件中设置了更多要写入的字节数,并且代码遵守了它。简而言之,在 iocb 的 bytes 字段中,要准确地写入 'hw' 需要不超过 2 个字节。

最佳答案

这里发生了一些事情。首先,您提到的对齐要求是 512 字节或 4096 字节,具体取决于您的底层设备。尝试从 512 字节开始。它适用于:

  1. 您在文件中写入的偏移量必须是 512 字节的倍数。它可以是 0、512、1024 等。您可以像这里一样在偏移量 0 处写入,但不能在偏移量 100 处写入。

  2. 写入文件的数据长度必须是 512 字节的倍数。同样,您可以写入 512 字节、1024 字节或 2048 字节等等 - 512 的任意倍数。您不能像此处尝试的那样写入 100 字节。

  3. 包含您正在写入的数据的内存地址必须是 512 的倍数。(为了安全起见,我通常使用 4096。)在这里,您需要能够执行 someBuffer % 512 和得到 0。(按照现在的代码,很可能不会。)

根据我的经验,未能满足上述任何要求实际上并不会返回错误!相反,它将使用正常的、常规的旧阻塞 I/O 来完成 I/O 请求。

未对齐的 I/O:如果您真的、真的需要写入少量数据或以未对齐的偏移量写入,那么即使在 io_submit 接口(interface)之上和之外,事情也会变得棘手。您需要进行对齐读取以覆盖您需要写入的数据范围,然后修改内存中的数据并将对齐区域写回磁盘。

例如,假设您想修改磁盘上从 768 到 1023 的偏移量。您需要将偏移量 512 处的 512 个字节读入缓冲区。然后,memcpy() 将 256 字节写入该缓冲区的 256 字节。最后,您在偏移量 512 处发出 512 字节缓冲区的写入。

未初始化的数据:正如其他人所指出的,您还没有完全初始化您正在编写的缓冲区。使用 memset() 将其初始化为零以避免写入垃圾。

分配对齐指针:为了满足数据缓冲区的指针要求,您需要使用 posix_memalign() 。例如,要分配 4096 字节且对齐限制为 512 字节:posix_memalign(&ptr, 512, 4096);

最后,考虑您是否需要这样做。即使在最好的情况下,io_submit 仍然会“阻塞”,尽管是在 10 到 100 微秒的级别。带有 preadpwrite 的普通阻塞 I/O 为您的应用程序提供了很多好处。而且,如果它变得繁重,您可以将其委托(delegate)给另一个线程。如果您有一个对延迟敏感的应用程序,您无论如何都需要在另一个线程中执行 io_submit!

关于c - 使用 Linux AIO,能够执行 IO,但也会将垃圾写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45735455/

相关文章:

在 C 中创建矩阵

c - GUI 的资源文件或 'CreateWindow' 函数?

java - linux top命令CPU使用率不加起来/如何实时查看Java线程使用率?

linux - 安卓O移植

c - 在这个函数中正确的指针没有返回到调用函数

c++ - Tizen 的母语是什么?

c - 堆栈溢出与堆栈崩溃

c - 从设备属性读取时调试在 container_of 上失败的简单字符驱动程序

c++ - 将变量中的值取消引用为指针地址

c++ - 指向指针/C++ 的指针中的数据类型声明意义)