이 블로그 검색

2012년 10월 26일 금요일

Linux Asynchronous I/O 예제


지금 프로젝트에서 작성한 프로그램의 개선점을 찾다보니, 비동기 작업 처리를 위해 aio를 이용하면 좋을듯 하다. 아래 사이트 내용을 참조하여 완전한 예제로 구성해보았다.
http://www.ibm.com/developerworks/linux/library/l-async/


컴파일은 gcc -lrt -o aioTest aioTest.c 으로 수행.

file.txt 내용은 다음과 같다.

123456789abcdefghijklmnopqrstuvwxyz


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//aioTest.c
#include <aio.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

// gcc -lrt -o aioTest aioTest.c
// librt" stands for "real time library".

//////////////////////////////////////////////////////////////////
// busy-wait until the status changes
void testBusyWait()
{
    printf("\n\n==================================================\n");
    int fd, ret;
    //int BUFSIZE = 10240;
    int BUFSIZE = 5;
    struct aiocb my_aiocb;

    fd = open( "file.txt", O_RDONLY );
    if (fd < 0) perror("open");

    /* Zero out the aiocb structure (recommended) */
    bzero( (char *)&my_aiocb, sizeof(struct aiocb) );

    /* Allocate a data buffer for the aiocb request */
    my_aiocb.aio_buf = malloc(BUFSIZE+1);

    if (!my_aiocb.aio_buf) perror("malloc");

    /* Initialize the necessary fields in the aiocb */
    my_aiocb.aio_fildes = fd;
    my_aiocb.aio_nbytes = BUFSIZE;
    my_aiocb.aio_offset = 0; //the first offset in the file

    //below block aio /////////////////////////////////
    int MAX_LIST = 1;
    struct aioct *cblist[MAX_LIST];
    /* Clear the list. */
    bzero( (char *)cblist, sizeof(cblist) );
    /* Load one or more references into the list */
    cblist[0] = &my_aiocb;
    //below block aio /////////////////////////////////
    ret = aio_read( &my_aiocb );

    //below block aio /////////////////////////////////
    ret = aio_suspend( cblist, MAX_LIST, NULL );
    //below block aio /////////////////////////////////

    if (ret < 0) perror("aio_read");

    while ( aio_error( &my_aiocb ) == EINPROGRESS )
    {
        printf("busy waiting...\n");
    }

    if ((ret = aio_return( &my_aiocb )) > 0)
    {
        /* got ret bytes on the read */
        printf("ret [%d]\n", ret);
        //print buffer
        printf("buff[%s]\n",my_aiocb.aio_buf);
    }
    else
    {
        /* read failed, consult errno */
        printf("read failed\n");
    }
}

//////////////////////////////////////////////////////////////////
// lio_listio , Initiate a list of I/O operations
// with busy waiting
void testListio()
{
    printf("\n\n==================================================\n");
    int fd, ret;
    //int BUFSIZE = 10240;
    int BUFSIZE = 5;
    int MAX_LIST = 2;
    struct aiocb aiocb1, aiocb2;
    struct aiocb *list[MAX_LIST];

    fd = open( "file.txt", O_RDONLY );
    if (fd < 0) perror("open");

    /* Zero out the aiocb structure (recommended) */
    bzero( (char *)&aiocb1, sizeof(struct aiocb) );
    bzero( (char *)&aiocb2, sizeof(struct aiocb) );

    //aiocb1
    aiocb1.aio_fildes = fd;
    aiocb1.aio_buf = malloc(BUFSIZE+1);
    aiocb1.aio_nbytes = BUFSIZE;
    aiocb1.aio_offset = 0; //the first offset in the file
    aiocb1.aio_lio_opcode = LIO_READ;
    //aiocb2
    aiocb2.aio_fildes = fd;
    aiocb2.aio_buf = malloc(BUFSIZE+1);
    aiocb2.aio_nbytes = BUFSIZE;
    aiocb2.aio_offset = BUFSIZE; //!!!
    aiocb2.aio_lio_opcode = LIO_READ;

    bzero( (char *)list, sizeof(list) );
    list[0] = &aiocb1;
    list[1] = &aiocb2;

    //WAIT
    //ret = lio_listio( LIO_WAIT, list, MAX_LIST, NULL );

    // NO_WAIT
    ret = lio_listio( LIO_NOWAIT, list, MAX_LIST, NULL );
    while ( aio_error( &aiocb1 ) == EINPROGRESS ||
      aio_error( &aiocb2 ) == EINPROGRESS )
    {
        printf("busy waiting...\n");
    }
    // NO_WAIT

    //aiocb1
    if ((ret = aio_return( &aiocb1 )) > 0)
    {
        printf("\n******\n");
        printf("aiocb1 ret [%d]\n", ret);
        printf("aiocb1 buff[%s]\n",aiocb1.aio_buf);
    }
    else
    {
        /* read failed, consult errno */
        printf("aiocb1 read failed\n");
    }
    //aiocb2
    if ((ret = aio_return( &aiocb2 )) > 0)
    {
        printf("\n******\n");
        printf("aiocb2 ret [%d]\n", ret);
        printf("aiocb2 buff[%s]\n",aiocb2.aio_buf);
    }
    else
    {
        /* read failed, consult errno */
        printf("aiocb2 read failed\n");
    }
}

//////////////////////////////////////////////////////////////////
//aio with callback
//also available : Asynchronous notification with signals

struct aiocb my_aiocb; 

void aio_completion_handler( sigval_t sigval )
{
    printf("aio_completion_handler\n");
    struct aiocb *req;

    req = (struct aiocb *)sigval.sival_ptr;

    /* Did the request complete? */
    if (aio_error( req ) == 0) {

        /* Request completed successfully, get the return status */
        int ret = aio_return( req );
        printf("ret [%d]\n", ret);
        printf("buff[%s]\n",req->aio_buf);
    }
    return;
}


void testCallback()
{
    printf("\n\n==================================================\n");
    int fd, ret;
    //int BUFSIZE = 10240;
    int BUFSIZE = 20;

    fd = open( "file.txt", O_RDONLY );
    if (fd < 0) perror("open");

    /* Set up the AIO request */
    bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
    my_aiocb.aio_fildes = fd;
    my_aiocb.aio_buf = malloc(BUFSIZE+1);
    my_aiocb.aio_nbytes = BUFSIZE;
    my_aiocb.aio_offset = 0;

    /* Link the AIO request with a thread callback */
    my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
    my_aiocb.aio_sigevent.sigev_notify_function = aio_completion_handler;
    my_aiocb.aio_sigevent.sigev_notify_attributes = NULL;
    my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;

    ret = aio_read( &my_aiocb );
}


//////////////////////////////////////////////////////////////////
int main(int argc,char** argv)
{
    testBusyWait();
    testListio();
    testCallback();

    while(1)
    {
        sleep(1);
    }
}

수행 결과는 다음과 같다.

==============================================================
ret [5]
buff[12345]

==============================================================
aiocb1 busy waiting...
aiocb1 busy waiting...
.....
aiocb1 busy waiting...

******

aiocb1 ret [5]
aiocb1 buff[12345]

******

aiocb2 ret [5]
aiocb2 buff[6789a]

==============================================================
aio_completion_handler
ret [20]
buff[123456789abcdefghijk]

댓글 1개:

  1. 글 잘 보았습니다.
    aio library와 libaio library의 차이점이 있네요. 아래글 참고하세요~^^

    http://stackoverflow.com/questions/8768083/difference-between-posix-aio-and-libaio-on-linux

    답글삭제