0

我想使用 aio_write 写入 2 个文件。

使用 32KB 缓冲区并为 1 个文件重复 aio_write 2048 次。(文件大小为 64MB)

但是,现在结果不是 64MB,而是大小为 64MB + 32KB。

有时文件也是由垃圾写入的。我想填写“A”来归档。

请帮我。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <aio.h>
#include <fcntl.h>
#include <siginfo.h>

#define TNAME           "testAio.c"
#define BUFFER_SIZE     32 * 1024 //(32 * 1024 * 1024)
#define FILE_COUNT      2
#define FILE_PATH       256
#define FALSE           0
#define TRUE            1

int main ()
{
    char           sTmpFileName[FILE_COUNT][FILE_PATH];
    char         * sBuf;
    char         * sAlignedBuf;
    int           sFd[FILE_COUNT];
    struct aiocb  sAiocb[FILE_COUNT];
    int           sError;
    int           sRet;
    int           i;
    int           j;
    int           sWritten[FILE_COUNT];
    int           sWrittenSize;
    int           sWrittenCnt;
    int           sFrequence = 2048;

    sBuf = (char*) malloc( BUFFER_SIZE + 512 );

sAlignedBuf = (char*)( ((long)sBuf) + (512 -  ((long)sBuf) % 512));

    memset( sAlignedBuf, 0x41, BUFFER_SIZE );

    for( i = 0; i < FILE_COUNT; i++ )
    {
        memset( &sAiocb[i], 0, sizeof(struct aiocb) );

        sAiocb[i].aio_buf = sAlignedBuf;
        sAiocb[i].aio_nbytes = BUFFER_SIZE;

        snprintf( sTmpFileName[i],
                  FILE_PATH,
                  "testAio_%d",
                  i);

        unlink( sTmpFileName[i] );

        sFd[i] = open( sTmpFileName[i],
                       O_CREAT | O_RDWR | O_EXCL |
                       O_DIRECT | O_LARGEFILE,
                       S_IRUSR | S_IWUSR );

        sAiocb[i].aio_fildes = sFd[i];

        if( sFd[i] == -1 )
        {
            printf( TNAME " Error at open(): %s\n", strerror( errno ) );
            exit(1);
        }
    }

    for( j = 0; j < sFrequence; j++ )
    {
        for( i = 0; i < FILE_COUNT; i++ )
        {
            if( sWrittenSize = aio_write( &sAiocb[i] ) == -1 )
            {
                printf( TNAME " Error at aio_write(): %s\n", strerror( errno ) );

                close( sFd[i] );

                exit(2);
            }

            sAiocb[i].aio_offset += sAiocb[i].aio_nbytes;

            // printf( "offset %ld\n", sAiocb[i].aio_offset );
        }
    }

    printf( "offset %ld %ld\n",
            sAiocb[0].aio_offset,
            sAiocb[1].aio_offset );

    /* Wait until completion */
    i = 0;
    sWritten[0] = FALSE;
    sWritten[1] = FALSE;
    sWrittenCnt = 0;
    while( 1 )
    {
        sError = aio_error( &sAiocb[i] );

        if( sError != EINPROGRESS )
        {
            if( sWritten[i] == FALSE )
            {
                sWrittenCnt++;
                sWritten[i] = TRUE;
            }
        }

        if( sWrittenCnt == FILE_COUNT )
        {
            break;
        }

        i = (i + 1) % FILE_COUNT;
    }


    for( i = 0; i < FILE_COUNT; i++ )
    {
        sError = aio_error( &sAiocb[i] );
        sRet = aio_return( &sAiocb[i] );

        if( sError != 0 )
        {

            printf( TNAME " Error at aio_error() : %d, %s\n",
                    i,
                    strerror( sError ) );

            close( sFd[i] );

            exit(2);
        }

        if( sRet != BUFFER_SIZE )
        {
            printf( TNAME " Error at aio_return()\n" );

            close( sFd[i] );

            exit(2);
        }
    }

    for( i = 0; i < FILE_COUNT; i++ )
    {
        close( sFd[i] );
    }

    printf( "Test PASSED\n" );

    return 0;
}
4

2 回答 2

1

大多数 POSIX 实现对并发异步 i/o 操作的数量实施严格限制,这些操作可以在系统上和每个进程中运行。在某些主要实现上,此限制为 16。因此,您不能简单地aio_write按顺序调用 2048 次,您必须只调用它直到AIO_LISTIO_MAX最大可能,始终在最大可能限制之前检查系统资源耗尽的错误代码。即使在没有硬性限制的 NT 上,在开启一定数量的并发后性能也会明显下降FILE_FLAG_NO_BUFFERING,尤其是在较旧的 Windows 内核上。

一旦您安排aio_write了系统所需的数量,您就需要调用aio_suspend您已安排的内容并退出所有已完成的操作,再次尝试重新填充待处理的 i/o 队列。如果您想查看使用的生产示例,请尝试https://github.com/ned14/boost.afio/blob/master/include/boost/afio/v2.0/detail/impl/posix/io_service。 ipp _

我应该强调,POSIX aio 的扩展性很差,几乎没有提供任何性能优势,并且在 Linux 或 FreeBSD 上,您的“异步 i/o”实际上是一个线程池,它为您调用同步 i/o API。几乎没有 POSIX 操作系统在实践中实现了很多异步性,除非O_DIRECT打开或打开它的等价物,它只有在 NT 上才真正值得费心。

正如 Stackoverflow 上的许多其他帖子所说,对于 99% 的用户来说,异步文件系统 i/o 不值得花时间和麻烦,只需使用调用同步 API 的线程池,它的扩展性要好得多,并且可以跨所有平台移植,信号方面没有愚蠢的问题,而且总是在 Linux 或 FreeBSDO_DIRECT上关闭,这就是 POSIX aio 的实现方式。

于 2016-08-16T07:53:11.480 回答
0

感谢您的评论。
现在我注意到我犯了错误的代码。

我不知道这是否确定。
我假设 aio_nbytes 应该同时处理。

在我为某个文件(例如 file1)调用 aio_write 之后,我必须等到调用结束后才能对 file1 进行下一个 aio_write 调用。

我的假设对吗?

于 2016-08-16T08:22:04.107 回答