C 带回调函数的AIO异步I/O——寻找最佳方法

C 带回调函数的AIO异步I/O——寻找最佳方法,c,asynchronous,signals,posix,aio,C,Asynchronous,Signals,Posix,Aio,我正在尝试学习POSIX异步I/O。下面是我对其他人的示例代码所做的编辑。我想了解一些事情 首先,我在末尾有一个繁忙的等待循环,它关闭了intread\u complete。这是一种“可接受”(安全的,无论如何,…)的替代方法,而不是关闭aio_error()的返回值?另外,我在想,作为繁忙等待循环的替代方法,有一种方法可以让主线程进入睡眠状态,并让回调函数发送某种信号来唤醒它。但我不知道该怎么做,如果可以的话 最后,我试图找出如何在回调函数I\u am\u done中获取更多信息。例如,假设我

我正在尝试学习
POSIX
异步I/O。下面是我对其他人的示例代码所做的编辑。我想了解一些事情

首先,我在末尾有一个繁忙的等待循环,它关闭了
int
read\u complete
。这是一种“可接受”(安全的,无论如何,…)的替代方法,而不是关闭
aio_error()
的返回值?另外,我在想,作为繁忙等待循环的替代方法,有一种方法可以让主线程进入睡眠状态,并让回调函数发送某种信号来唤醒它。但我不知道该怎么做,如果可以的话

最后,我试图找出如何在回调函数
I\u am\u done
中获取更多信息。例如,假设我想将输入数据推送到一个缓冲区中,或者在缓冲区之间拆分,以便主线程稍后使用,如果我有多个读取任务,则每次调用的缓冲区可能不同。我怎样才能让
我完成了
知道缓冲区是什么

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <aio.h>
//#include <bits/stdc++.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#include <errno.h>

const int BUFSIZE = 1024;

int read_complete = 0;


void i_am_done(sigval_t sigval)
{
    struct aiocb *req;

    req = (struct aiocb *)sigval.sival_ptr; //Pay attention here.
    /*Check again if the asynchrony is complete?*/
    if (aio_error(req) == 0)
    {
        read_complete = 1;

    }
    close(req->aio_fildes);


}



int main(void)
{
    struct aiocb my_aiocb;
    struct timeval t0, t1;


    int fd = open("file.txt", O_RDONLY);
    if (fd < 0)
        perror("open");
    bzero((char *)&my_aiocb, sizeof(my_aiocb));

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

    my_aiocb.aio_fildes = fd;
    my_aiocb.aio_nbytes = BUFSIZE;
    my_aiocb.aio_offset = 0;

    //Fill in callback information
    /*
    Using SIGEV_THREAD to request a thread callback function as a notification method
    */
    my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
    my_aiocb.aio_sigevent.sigev_notify_function = i_am_done;
    my_aiocb.aio_sigevent.sigev_notify_attributes = NULL;

    my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;

    int ret = aio_read(&my_aiocb);



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

    //The calling process continues to execute

    while (read_complete != 1) {}

    printf("main thread %s\n", (char*)my_aiocb.aio_buf);
    return 0;
}
#包括
#包括
#包括
#包括
//#包括
#包括
#包括
#包括
#包括
#包括
#包括
常量int BUFSIZE=1024;
int read_complete=0;
无效已完成(sigval t sigval)
{
结构aiocb*req;
req=(struct aiocb*)sigval.sival_ptr;//注意这里。
/*再次检查异步是否完成*/
如果(aio_错误(req)==0)
{
read_complete=1;
}
关闭(请求->aio_fildes);
}
内部主(空)
{
结构aiocb my_aiocb;
结构时间值t0,t1;
int fd=open(“file.txt”,仅限ordu);
如果(fd<0)
佩罗(“公开”);
bzero((char*)和my_aiocb,sizeof(my_aiocb));
my_aiocb.aio_buf=malloc(BUFSIZE);
如果(!my_aiocb.aio_buf)
佩罗尔(my_aiocb.aio_buf);
my_aiocb.aio_fildes=fd;
my_aiocb.aio_nbytes=BUFSIZE;
my_aiocb.aio_offset=0;
//填写回拨信息
/*
使用SIGEV_线程请求线程回调函数作为通知方法
*/
my_aiocb.aio_sigeevent.sigev_notify=sigev_线程;
my_aiocb.aio_sigevent.sigev_notify_function=i_am_done;
my_aiocb.aio_sigevent.sigev_notify_attributes=NULL;
my_aiocb.aio_sigevent.sigev_value.sival_ptr=&my_aiocb;
int ret=aio_read(&my_aiocb);
如果(ret<0)
perror(“aio_read”);
//调用进程将继续执行
while(read_complete!=1){
printf(“主线程%s\n”,(char*)my_aiocb.aio_buf);
返回0;
}
回答问题2,只需定义一个数据结构,将所需的附加数据存储到其中,然后将
sival_ptr
设置为该结构。例如:

struct my_data {
    struct aiocb cb;

    // For demonstration's sake:
    int foo;
    char *bar;
    size_t quux;
}

// ...

struct my_data data;
data.cb.aio_sigevent.sigev_value.sival_ptr = &data; 
// Setup the rest of the struct and execute the read.

在回调中,您现在可以访问my_数据结构。

wrt问题2;你到底是什么意思?您现在实际上是在“将输入数据推送到缓冲区”吗?或者你的意思是在回调中,你会将数据复制到其他地方?@vmt我的意思是在回调中,我会将数据复制到其他地方。例如,您可以看到回调将全局变量read_complete设置为1。我如何给回调一个特定的指针,指向我希望它设置的其他变量(可能是局部变量)?例如,对回调函数的不同调用可能会导致设置不同的变量,所以它就是这样工作的。谢谢令我感到惊讶的是,关于AIO这一一般主题的参考文献很少。你知道有什么好的吗?如果有必要,我会买一本书!aio的手册页有一个使用sigaction的示例。我不熟悉aio接口,但是您可以查看事件循环库,它提供了比aio接口多得多的控制和功能。libuv,libevent出现在我的脑海里。或者,您也可以考虑实现自己的循环库。我认为引用的稀缺性正是由于使用现有的事件循环库实现的流行,或者编写一个事件循环库的相对简单。libevent和libuv都有很多示例,如果您不需要所有功能(计时器等),那么有很多使用epoll(在linux上)和p)select等的简单事件循环示例。