aio(7) - wariua/manpages-ko GitHub Wiki

NAME

aio - POSIX 비동기 I/O μ†Œκ°œ

DESCRIPTION

POSIX 비동기 I/O(AIO) μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‘μš©μ—μ„œ μ΄μš©ν•˜μ—¬ λΉ„λ™κΈ°μ μœΌλ‘œ (즉 λ°°κ²½μ—μ„œ) μˆ˜ν–‰λ˜λŠ” I/O λ™μž‘μ„ ν•œ 개 이상 κ°œμ‹œν•  수 μžˆλ‹€. I/O λ™μž‘ μ™„λ£Œμ— λŒ€ν•œ μ•Œλ¦Όμ„ μ‘μš©μ—μ„œ μ›ν•˜λŠ” λ‹€μ–‘ν•œ λ°©μ‹μœΌλ‘œ 받을 수 μžˆλ‹€. μ‹œκ·Έλ„ 전달, μŠ€λ ˆλ“œ μ‹€ν–‰, λ˜λŠ” μ•Œλ¦Όμ„ λ°›μ§€ μ•Šμ„ μˆ˜λ„ μžˆλ‹€.

POSIX AIO μΈν„°νŽ˜μ΄μŠ€λŠ” λ‹€μŒ ν•¨μˆ˜λ“€λ‘œ 이뀄져 μžˆλ‹€.

aio_read(3)
읽기 μš”μ²­μ„ 큐에 λ„£λŠ”λ‹€. read(2)의 비동기 ν˜•νƒœμ΄λ‹€.
aio_write(3)
μ“°κΈ° μš”μ²­μ„ 큐에 λ„£λŠ”λ‹€. write(2)의 비동기 ν˜•νƒœμ΄λ‹€.
aio_fsync(3)
파일 λ””μŠ€ν¬λ¦½ν„° μƒμ˜ I/O λ™μž‘λ“€μ— λŒ€ν•œ 동기화 μš”μ²­μ„ 큐에 λ„£λŠ”λ‹€. fsync(2) 및 fdatasync(2)의 비동기 ν˜•νƒœμ΄λ‹€.
aio_error(3)
큐에 넣은 I/O μš”μ²­μ˜ 였λ₯˜ μƒνƒœλ₯Ό μ–»λŠ”λ‹€.
aio_return(3)
μ™„λ£Œλœ I/O μš”μ²­μ˜ λ°˜ν™˜ μƒνƒœλ₯Ό μ–»λŠ”λ‹€.
aio_suspend(3)
μ§€μ •ν•œ I/O μš”μ²­μ΄ ν•˜λ‚˜ 이상 μ™„λ£Œλ  λ•ŒκΉŒμ§€ 호좜자λ₯Ό λ©ˆμΆ˜λ‹€.
aio_cancel(3)
μ§€μ •ν•œ 파일 λ””μŠ€ν¬λ¦½ν„° μƒμ˜ 미처리 I/O μš”μ²­λ“€μ„ μ·¨μ†Œ μ‹œλ„ν•œλ‹€.
lio_listio(3)
ν•œ 번의 ν•¨μˆ˜ 호좜둜 μ—¬λŸ¬ I/O μš”μ²­μ„ 큐에 λ„£λŠ”λ‹€.

aiocb(비동기 I/O μ œμ–΄ 블둝) ꡬ쑰체가 I/O λ™μž‘μ„ μ œμ–΄ν•˜λŠ” λ§€κ°œλ³€μˆ˜λ“€μ„ μ •μ˜ν•œλ‹€. μœ„μ— λ‚˜μ—΄ν•œ ν•¨μˆ˜ λͺ¨λ‘μ—μ„œ 이 νƒ€μž…μ˜ 인자λ₯Ό μ“΄λ‹€. 이 κ΅¬μ‘°μ²΄λŠ” λ‹€μŒ ν˜•νƒœμ΄λ‹€.

#include <aiocb.h>

struct aiocb {
    /* 이 ν•„λ“œλ“€μ˜ μˆœμ„œλŠ” κ΅¬ν˜„μ— 따라 닀름 */

    int             aio_fildes;     /* 파일 λ””μŠ€ν¬λ¦½ν„° */
    off_t           aio_offset;     /* 파일 μ˜€ν”„μ…‹ */
    volatile void  *aio_buf;        /* 버퍼 μœ„μΉ˜ */
    size_t          aio_nbytes;     /* 전솑 길이 */
    int             aio_reqprio;    /* μš”μ²­ μš°μ„ μˆœμœ„ */
    struct sigevent aio_sigevent;   /* μ•Œλ¦Ό 방법 */
    int             aio_lio_opcode; /* μˆ˜ν–‰ν•  λ™μž‘.
                                       lio_listio()μ—μ„œλ§Œ */

    /* μ—¬λŸ¬ κ΅¬ν˜„ λ‚΄λΆ€μš© ν•„λ“œ μƒλž΅ */
};

/* 'aio_lio_opcode'의 λ™μž‘ μ½”λ“œ */

enum { LIO_READ, LIO_WRITE, LIO_NOP };

이 ꡬ쑰체의 ν•„λ“œλ“€μ€ λ‹€μŒκ³Ό κ°™λ‹€.

aio_fildes
I/O λ™μž‘μ„ μˆ˜ν–‰ν•  파일 λ””μŠ€ν¬λ¦½ν„°.
aio_offset
I/O λ™μž‘μ„ μˆ˜ν–‰ν•  파일 μ˜€ν”„μ…‹.
aio_buf
읽기 λ˜λŠ” μ“°κΈ° λ™μž‘μ—μ„œ 데이터 이동에 μ‚¬μš©ν•˜λŠ” 버퍼.
aio_nbytes
aio_bufκ°€ κ°€λ¦¬ν‚€λŠ” λ²„νΌμ˜ 크기.
aio_reqprio
이 ν•„λ“œμ— μ§€μ •ν•œ 값을 호좜 μŠ€λ ˆλ“œμ˜ μ‹€μ‹œκ°„ μš°μ„ μˆœμœ„μ—μ„œ λΉΌμ„œ 이 I/O μš”μ²­μ˜ μ‹€ν–‰ μš°μ„ μˆœμœ„λ₯Ό κ²°μ •ν•œλ‹€. (pthread_setschedparam(3) μ°Έκ³ .) μ§€μ •ν•˜λŠ” 값이 0κ³Ό sysconf(_SC_AIO_PRIO_DELTA_MAX) λ°˜ν™˜ κ°’ 사이에 μžˆμ–΄μ•Ό ν•œλ‹€. 파일 동기화 λ™μž‘μ—μ„œλŠ” 이 ν•„λ“œλ₯Ό λ¬΄μ‹œν•œλ‹€.
aio_sigevent
비동기 I/O λ™μž‘μ΄ μ™„λ£Œλμ„ λ•Œ ν˜ΈμΆœμžκ°€ μ•Œλ¦Όμ„ λ°›λŠ” 방법을 μ§€μ •ν•˜λŠ” ꡬ쑰체이닀. aio_sigevent.sigev_notify에 κ°€λŠ₯ν•œ 값은 SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD이닀. μžμ„Έν•œ λ‚΄μš©μ€ sigevent(7) μ°Έκ³ .
aio_lio_opcode
μˆ˜ν–‰ν•  λ™μž‘ μ’…λ₯˜. lio_listio(3)μ—μ„œλ§Œ μ‚¬μš©.

μœ„μ— λ‚˜μ—΄ν•œ ν‘œμ€€ ν•¨μˆ˜λ“€μ— λ”ν•΄μ„œ GNU C λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œλŠ” POSIX AIO API에 λŒ€ν•œ λ‹€μŒ ν™•μž₯을 μ œκ³΅ν•œλ‹€.

aio_init(3)
glibc POSIX AIO κ΅¬ν˜„μ˜ λ™μž‘μ„ μ‘°μ •ν•˜λŠ” λ§€κ°œλ³€μˆ˜λ“€μ„ μ„€μ •ν•œλ‹€.

ERRORS

EINVAL
aiocb ꡬ쑰체의 aio_reqprio ν•„λ“œκ°€ 0보닀 μž‘κ±°λ‚˜ sysconf(_SC_AIO_PRIO_DELTA_MAX) 호좜이 λ°˜ν™˜ν•œ ν•œκ³„μΉ˜λ³΄λ‹€ 크닀.

VERSIONS

glibc 버전 2.1λΆ€ν„° POSIX AIO μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•œλ‹€.

CONFORMING TO

POSIX.1-2001, POSIX.1-2008.

NOTES

μ œμ–΄ 블둝 버퍼λ₯Ό μ‚¬μš©ν•˜κΈ° 전에 0으둜 μ±„μš°λŠ” 게 μ’‹λ‹€. (memset(3) μ°Έκ³ .) I/O λ™μž‘μ΄ μ§„ν–‰ 쀑인 λ™μ•ˆ μ œμ–΄ 블둝 버퍼와 aio_bufκ°€ κ°€λ¦¬ν‚€λŠ” 버퍼가 λ³€κ²½λ˜μ–΄μ„  μ•ˆ λœλ‹€. I/O λ™μž‘μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ κ·Έ 버퍼듀이 μœ νš¨ν•œ μƒνƒœλ‘œ μœ μ§€λΌμ•Ό ν•œλ‹€.

같은 aiocb ꡬ쑰체λ₯Ό μ‚¬μš©ν•΄ λ™μ‹œμ— 비동기 읽기 λ™μž‘κ³Ό μ“°κΈ° λ™μž‘μ„ ν•  λ•Œ λ‚˜μ˜€λŠ” κ²°κ³ΌλŠ” κ·œμ •λΌ μžˆμ§€ μ•Šλ‹€.

ν˜„μž¬ λ¦¬λˆ…μŠ€μ˜ POSIX AIO κ΅¬ν˜„μ€ μ‚¬μš©μž κ³΅κ°„μ—μ„œ glibcκ°€ μ œκ³΅ν•œλ‹€. κ·Έλž˜μ„œ μ—¬λŸ¬ μ œμ•½μ΄ μžˆλŠ”λ°, κ°€μž₯ λˆˆμ— λ„λŠ” 건 I/O λ™μž‘μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ μŠ€λ ˆλ“œλ₯Ό μœ μ§€ν•˜λŠ” 게 λΉ„μš©μ΄ 크고 ν™•μž₯성이 λ–¨μ–΄μ§„λ‹€λŠ” 점이닀. μ–Όλ§ˆ μ „λΆ€ν„° μ»€λ„μ—μ„œ μƒνƒœ λ¨Έμ‹  기반으둜 비동기 I/Oλ₯Ό κ΅¬ν˜„ν•˜λŠ” μž‘μ—…μ΄ μ§„ν–‰ 쀑이긴 ν•œλ° (io_submit(2), io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2) μ°Έκ³ ) κ·Έ 컀널 μ‹œμŠ€ν…œ ν˜ΈμΆœλ“€μ„ μ΄μš©ν•΄ POSIX AIO κ΅¬ν˜„μ„ μ™„μ „νžˆ μž¬κ΅¬ν˜„ν•  수 μžˆλŠ” μˆ˜μ€€κΉŒμ§€λŠ” 아직 μ˜€μ§€ λͺ»ν–ˆλ‹€.

EXAMPLE

μ•„λž˜ ν”„λ‘œκ·Έλž¨μ—μ„œλŠ” λͺ…λ Ήν–‰ μΈμžμ— μ§€λͺ…ν•œ νŒŒμΌλ“€ 각각을 μ—΄μ–΄μ„œ 얻은 파일 λ””μŠ€ν¬λ¦½ν„°μ— aio_read(3)둜 μš”μ²­μ„ λ„£λŠ”λ‹€. κ·ΈλŸ¬κ³ μ„œ 루프λ₯Ό λŒλ©΄μ„œ 아직 μ§„ν–‰ 쀑인 I/O λ™μž‘ 각각을 aio_error(3)λ₯Ό μ΄μš©ν•΄ 주기적으둜 ν™•μΈν•œλ‹€. I/O μš”μ²­ 각각은 μ‹œκ·Έλ„ μ „λ‹¬λ‘œ μ•Œλ¦Όμ„ 주도둝 μ„€μ •ν•œλ‹€. λͺ¨λ“  I/O μš”μ²­μ΄ μ™„λ£Œλœ 후에 aio_return(3)으둜 μƒνƒœλ₯Ό κ°€μ Έμ˜¨λ‹€.

SIGQUIT μ‹œκ·Έλ„(Control-\ μž…λ ₯으둜 생성)을 μ£Όλ©΄ ν”„λ‘œκ·Έλž¨μ—μ„œ aio_cancel(3)둜 미처리 μš”μ²­ 각각의 μ·¨μ†Œλ₯Ό μš”μ²­ν•œλ‹€.

λ‹€μŒμ€ 이 ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰ν•œ κ²°κ³Ό μ˜ˆμ‹œμ΄λ‹€. 이 μ˜ˆμ—μ„œλŠ” ν‘œμ€€ μž…λ ₯에 λŒ€ν•œ μš”μ²­μ„ 두 개 ν•˜κ³ , "abc"와 "x"λ₯Ό 담은 두 μž…λ ₯ ν–‰μœΌλ‘œ κ·Έ μš”μ²­μ„ μΆ©μ‘±μ‹œν‚¨λ‹€.

$ ./a.out /dev/stdin /dev/stdin
opened /dev/stdin on descriptor 3
opened /dev/stdin on descriptor 4
aio_error():
    for request 0 (descriptor 3): In progress
    for request 1 (descriptor 4): In progress
abc
I/O completion signal received
aio_error():
    for request 0 (descriptor 3): I/O succeeded
    for request 1 (descriptor 4): In progress
aio_error():
    for request 1 (descriptor 4): In progress
x
I/O completion signal received
aio_error():
    for request 1 (descriptor 4): I/O succeeded
All I/O requests completed
aio_return():
    for request 0 (descriptor 3): 4
    for request 1 (descriptor 4): 2

ν”„λ‘œκ·Έλž¨ μ†ŒμŠ€

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <aio.h>
#include <signal.h>

#define BUF_SIZE 20     /* 읽기 λ™μž‘μ„ μœ„ν•œ 버퍼 크기 */

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define errMsg(msg)  do { perror(msg); } while (0)

struct ioRequest {      /* I/O μš”μ²­ 좔적을 μœ„ν•΄ μ‘μš© μžμ²΄μ—μ„œ
                           μ •μ˜ν•˜λŠ” ꡬ쑰체 */
    int           reqNum;
    int           status;
    struct aiocb *aiocbp;
};

static volatile sig_atomic_t gotSIGQUIT = 0;
                        /* SIGQUIT이 μ „λ‹¬λ˜λ©΄ 미처리 I/O μš”μ²­μ„
                           λͺ¨λ‘ μ·¨μ†Œν•˜λ €κ³  μ‹œλ„ */

static void             /* SIGQUIT ν•Έλ“€λŸ¬ */
quitHandler(int sig)
{
    gotSIGQUIT = 1;
}

#define IO_SIGNAL SIGUSR1   /* I/O μ™„λ£Œλ₯Ό μ•Œλ¦¬λŠ” 데 μ“Έ μ‹œκ·Έλ„ */

static void                 /* I/O μ™„λ£Œ μ‹œκ·Έλ„ ν•Έλ“€λŸ¬ */
aioSigHandler(int sig, siginfo_t *si, void *ucontext)
{
    if (si->si_code == SI_ASYNCIO) {
        write(STDOUT_FILENO, "I/O completion signal received\n", 31);

        /* λŒ€μ‘ν•˜λŠ” ioRequest ꡬ쑰체λ₯Ό λ‹€μŒκ³Ό 같이 얻을 수 있음:
               struct ioRequest *ioReq = si->si_value.sival_ptr;
           그리고 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό λ‹€μŒμ„ 톡해 얻을 수 있음:
               ioReq->aiocbp->aio_fildes */
    }
}

int
main(int argc, char *argv[])
{
    struct ioRequest *ioList;
    struct aiocb *aiocbList;
    struct sigaction sa;
    int s, j;
    int numReqs;        /* 큐에 넣은 I/O μš”μ²­ 총 개수 */
    int openReqs;       /* 아직 μ§„ν–‰ 쀑인 I/O μš”μ²­ 개수 */

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",
                argv[0]);
        exit(EXIT_FAILURE);
    }

    numReqs = argc - 1;

    /* λ°°μ—΄ ν• λ‹Ή */

    ioList = calloc(numReqs, sizeof(struct ioRequest));
    if (ioList == NULL)
        errExit("calloc");

    aiocbList = calloc(numReqs, sizeof(struct aiocb));
    if (aiocbList == NULL)
        errExit("calloc");

    /* SIGQUIT 및 I/O μ™„λ£Œ μ‹œκ·Έλ„μ„ μœ„ν•œ ν•Έλ“€λŸ¬ μ„€μ • */

    sa.sa_flags = SA_RESTART;
    sigemptyset(&sa.sa_mask);

    sa.sa_handler = quitHandler;
    if (sigaction(SIGQUIT, &sa, NULL) == -1)
        errExit("sigaction");

    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    sa.sa_sigaction = aioSigHandler;
    if (sigaction(IO_SIGNAL, &sa, NULL) == -1)
        errExit("sigaction");

    /* λͺ…령행에 μ§€μ •ν•œ 파일 각각을 μ—΄κ³ , κ·Έλ ‡κ²Œ 얻은 파일
       λ””μŠ€ν¬λ¦½ν„°μ—μ„œ 읽기 μš”μ²­μ„ 큐에 λ„£κΈ° */

    for (j = 0; j < numReqs; j++) {
        ioList[j].reqNum = j;
        ioList[j].status = EINPROGRESS;
        ioList[j].aiocbp = &aiocbList[j];

        ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY);
        if (ioList[j].aiocbp->aio_fildes == -1)
            errExit("open");
        printf("opened %s on descriptor %d\n", argv[j + 1],
                ioList[j].aiocbp->aio_fildes);

        ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);
        if (ioList[j].aiocbp->aio_buf == NULL)
            errExit("malloc");

        ioList[j].aiocbp->aio_nbytes = BUF_SIZE;
        ioList[j].aiocbp->aio_reqprio = 0;
        ioList[j].aiocbp->aio_offset = 0;
        ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
        ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;
        ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =
                                &ioList[j];

        s = aio_read(ioList[j].aiocbp);
        if (s == -1)
            errExit("aio_read");
    }

    openReqs = numReqs;

    /* 루프 λŒλ©΄μ„œ I/O μš”μ²­ μƒνƒœ 확인 */

    while (openReqs > 0) {
        sleep(3);       /* 확인 간격 */

        if (gotSIGQUIT) {

            /* SIGQUIT μˆ˜μ‹  μ‹œ 미처리 I/O μš”μ²­ 각각을 μ·¨μ†Œ μ‹œλ„ν•˜κ³ ,
               μ·¨μ†Œ μš”μ²­μ—μ„œ λ°˜ν™˜ 받은 μƒνƒœλ₯Ό ν‘œμ‹œ */

            printf("got SIGQUIT; canceling I/O requests: \n");

            for (j = 0; j < numReqs; j++) {
                if (ioList[j].status == EINPROGRESS) {
                    printf("    Request %d on descriptor %d:", j,
                            ioList[j].aiocbp->aio_fildes);
                    s = aio_cancel(ioList[j].aiocbp->aio_fildes,
                            ioList[j].aiocbp);
                    if (s == AIO_CANCELED)
                        printf("I/O canceled\n");
                    else if (s == AIO_NOTCANCELED)
                        printf("I/O not canceled\n");
                    else if (s == AIO_ALLDONE)
                        printf("I/O all done\n");
                    else
                        errMsg("aio_cancel");
                }
            }

            gotSIGQUIT = 0;
        }

        /* 아직 μ§„ν–‰ 쀑인 I/O μš”μ²­ 각각의 μƒνƒœ 확인 */

        printf("aio_error():\n");
        for (j = 0; j < numReqs; j++) {
            if (ioList[j].status == EINPROGRESS) {
                printf("    for request %d (descriptor %d): ",
                        j, ioList[j].aiocbp->aio_fildes);
                ioList[j].status = aio_error(ioList[j].aiocbp);

                switch (ioList[j].status) {
                case 0:
                    printf("I/O succeeded\n");
                    break;
                case EINPROGRESS:
                    printf("In progress\n");
                    break;
                case ECANCELED:
                    printf("Canceled\n");
                    break;
                default:
                    errMsg("aio_error");
                    break;
                }

                if (ioList[j].status != EINPROGRESS)
                    openReqs--;
            }
        }
    }

    printf("All I/O requests completed\n");

    /* λͺ¨λ“  I/O μš”μ²­μ˜ μƒνƒœ λ°˜ν™˜ κ°’ 확인 */

    printf("aio_return():\n");
    for (j = 0; j < numReqs; j++) {
        ssize_t s;

        s = aio_return(ioList[j].aiocbp);
        printf("    for request %d (descriptor %d): %zd\n",
                j, ioList[j].aiocbp->aio_fildes, s);
    }

    exit(EXIT_SUCCESS);
}

SEE ALSO

io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2), aio_cancel(3), aio_error(3), aio_init(3), aio_read(3), aio_return(3), aio_write(3), lio_listio(3)

"Asynchronous I/O Support in Linux 2.5", Bhattacharya, Pratt, Pulavarty, and Morgan, Proceedings of the Linux SYmposium, 2003, https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf


2019-03-06

⚠️ **GitHub.com Fallback** ⚠️