您的位置:首页 > 运维架构 > Linux

TLPI-Chapter 13文件I/O缓冲

2017-10-29 18:03 411 查看
函数:
void *memalign(size_t alignment, size_t size);


The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory address will be a multiple of alignment, which must be a power of two.


memalign 分配 size 字节的空间,返回指向该空间的指针,空间的地址是 alignment 的倍数,alignment 必须是 2 的乘幂。

Lunix/UNIX系统编程手册提供的示例代码中的解释如下:

/* memalign() allocates a block of memory aligned on an address that  is a multiple of its first argument. By specifying this argument as 2 * 'alignment' and then adding 'alignment' to the returned pointer,we ensure that 'buf' is aligned on a non-power-of-two multiple of'alignment'. We do this to ensure that if, for example, we ask for a 256-byte aligned buffer, we don't accidentally get a buffer that is also aligned on a 512-byte boundary. */


总结

输入输出数据的缓冲由内核和stdio库完成。有时希望阻止缓冲,但这需要了解其对应用程序性能的影响。可以使用各种系统调用和库函数来控制内核和stdio换从,并执行一次性的缓冲区刷新。

进程使用posix_fadvise()函数,可就进程对特定文件可能采取的数据访问模式向内核提出建议。内核可藉此来优化对换从去告诉缓存的应用,进而提高I/O性能。

在Linux环境下,open()所特有的O_DIRECT标识,允许特定应用跳过缓冲区告诉缓存、

在对同一个文件执行I/O操作时,fileno()和fdopen()有助于系统调用和标准C语言库函数的混合使用。给定一个流,fileno()将返回相应的文件描述符,fdopen()则针对指定的打开文件描述符创建一个新的流。



图13-1是本章的重点。该图概括了stdio函数库和内核所采用的缓冲,以及对各种缓冲类型的控制机制。从图中自上而下,首先是通过stdio库将用户数据传递到stdio缓冲区,该缓冲区位于用户态内存区。当缓冲区填满时,stdio库会调用write()系统调用,将数据传递到内核高速缓冲区(位于内核态内存区)。最终内核发起磁盘操作,将数据传递到磁盘。

图13-1左侧所示为可于任何时刻显示强制刷新各类缓冲区的调用。图右侧所示为促使刷新自动化的调用:一是通过金庸stdio库的缓冲,二是在文件输出类的系统调用中启用同步,从而使每个write()调用立刻刷新到磁盘。

第13章中的示例代码如下:

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2015.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Listing 13-1 */

/* direct_read.c

Demonstrate the use of O_DIRECT to perform I/O bypassing the buffer cache
("direct I/O").

Usage: direct_read file length [offset [alignment]]

This program is Linux-specific.
*/
#define _GNU_SOURCE     /* Obtain O_DIRECT definition from <fcntl.h> */
#include <fcntl.h>
#include <malloc.h>
#include "tlpi_hdr.h"

int
main(int argc, char *argv[])
{
int fd;
ssize_t numRead;
size_t length, alignment;
off_t offset;
char *buf;

if (argc < 3 || strcmp(argv[1], "--help") == 0)
usageErr("%s file length [offset [alignment]]\n", argv[0]);

length = getLong(argv[2], GN_ANY_BASE, "length");
offset = (argc > 3) ? getLong(argv[3], GN_ANY_BASE, "offset") : 0;
alignment = (argc > 4) ? getLong(argv[4], GN_ANY_BASE, "alignment") : 4096;

fd = open(argv[1], O_RDONLY | O_DIRECT);
if (fd == -1)
errExit("open");

/* memalign() allocates a block of memory aligned on an address that
is a multiple of its first argument. By specifying this argument as
2 * 'alignment' and then adding 'alignment' to the returned pointer,
we ensure that 'buf' is aligned on a non-power-of-two multiple of
'alignment'. We do this to ensure that if, for example, we ask
for a 256-byte aligned buffer, we don't accidentally get
a buffer that is also aligned on a 512-byte boundary. */

buf = memalign(alignment * 2, length + alignment);
if (buf == NULL)
errExit("memalign");

buf += alignment;

if (lseek(fd, offset, SEEK_SET) == -1)
errExit("lseek");

numRead = read(fd, buf, length);
if (numRead == -1)
errExit("read");
printf("Read %ld bytes\n", (long) numRead);

exit(EXIT_SUCCESS);
}


该程序在open文件的时候传入O_DIRECT标志,绕过缓冲区高速缓存直接I/O.

但是存在如下限制:

用于传递数据的缓冲区,其内存边界必须对齐为块大小的整数倍。

用于传输数据的缓冲区,其内存边界必须为快大小的整数倍。

待传输数据的长度必须是块大小的整数倍。

如果不遵守上述任一条,将导致EINVAL错误。块大小(block size)指设备的物理块大小,通常为512字节.

执行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息