函数: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字节.
执行结果: