Demo1,使用aio_suspend轮循IO状态

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

int main(int argc, char *argv[])
{
	int fd, ret;
	struct aiocb cb = {};
	const struct aiocb *cbs[1] = {};

	if (argc < 2)
	{
		printf("Usage: %s <file>\n", argv[0]);
		return 1;
	}
	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
	{
		perror("open()");
		return 1;
	}

	cb.aio_fildes = fd;
	cb.aio_lio_opcode = LIO_READ;
	cb.aio_buf = malloc(10241);
	cb.aio_nbytes = 10240;
	aio_read(&cb);
	cbs[0] = &cb;
	
	while (1)
	{
		ret = aio_suspend(cbs, 1, NULL);
		if (ret == -1)
		{
			if (errno == EAGAIN)
			{
				continue;
			}
			else
			{
				perror("aio_suspend()");
				break;
			}
		}
		break;
	}
	if (aio_error(cbs[0]))
	{
		perror("aio_error()");
	}
	else
	{
		printf("%s", (char *)cbs[0]->aio_buf);
	}

	free((void *)cbs[0]->aio_buf);
	close(fd);
	return 0;
}

Dem2,使用信号回调函数获得IO完成事件

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

void sig_handle_func(int signo, siginfo_t *info, void *context)
{
	struct aiocb *cbp;

	cbp = (struct aiocb *)info->si_ptr;
	if (aio_error(cbp))
	{
		perror("aio_error()");
	}
	else
	{
		printf("%s", (char *)cbp->aio_buf);
	}
}

int main(int argc, char *argv[])
{
	int fd, ret;
	struct aiocb cb = {};
	struct sigaction act = {};
	sigset_t set;

	if (argc < 2)
	{
		printf("Usage: %s <file>\n", argv[0]);
		return 1;
	}

	sigemptyset(&act.sa_mask);
	act.sa_flags = SA_SIGINFO;
	act.sa_sigaction = sig_handle_func;
	sigaction(SIGIO, &act, NULL);

	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
	{
		perror("open()");
		return 1;
	}

	cb.aio_fildes = fd;
	cb.aio_lio_opcode = LIO_READ;
	cb.aio_buf = malloc(10241);
	cb.aio_nbytes = 10240;
	cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
	cb.aio_sigevent.sigev_signo = SIGIO;
	cb.aio_sigevent.sigev_value.sival_ptr = (void *)&cb;
	aio_read(&cb);

	sleep(3);

	free((void *)cb.aio_buf);
	close(fd);
	return 0;
}

Demo3,使用信号等待函数等待IO完成信号

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

int main(int argc, char *argv[])
{
	int fd, ret;
	struct aiocb cb = {};
	struct sigaction act = {};
	sigset_t set;

	if (argc < 2)
	{
		printf("Usage: %s <file>\n", argv[0]);
		return 1;
	}

	sigemptyset(&set);
	sigaddset(&set, SIGIO);
	sigprocmask(SIG_BLOCK, &set, NULL);

	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
	{
		perror("open()");
		return 1;
	}

	cb.aio_fildes = fd;
	cb.aio_lio_opcode = LIO_READ;
	cb.aio_buf = malloc(10241);
	cb.aio_nbytes = 10240;
	cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
	cb.aio_sigevent.sigev_signo = SIGIO;
	cb.aio_sigevent.sigev_value.sival_ptr = (void *)&cb;
	aio_read(&cb);

	sigwaitinfo(&set, NULL);
	if (aio_error(&cb))
	{
		perror("aio_error()");
	}
	else
	{
		printf("%s", (char *)cb.aio_buf);
	}

	free((void *)cb.aio_buf);
	close(fd);
	return 0;
}

Demo4,通过新线程通知IO完成事件

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

void notify_func(sigval_t sv)
{
	struct aiocb *cbp;

	cbp = (struct aiocb *)sv.sival_ptr;
	if (aio_error(cbp))
	{
		perror("aio_error()");
	}
	else
	{
		printf("%s", (char *)cbp->aio_buf);
	}
}

int main(int argc, char *argv[])
{
	int fd, ret;
	struct aiocb cb = {};

	if (argc < 2)
	{
		printf("Usage: %s <file>\n", argv[0]);
		return 1;
	}
	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
	{
		perror("open()");
		return 1;
	}

	cb.aio_fildes = fd;
	cb.aio_lio_opcode = LIO_READ;
	cb.aio_buf = malloc(10241);
	cb.aio_nbytes = 10240;
	cb.aio_sigevent.sigev_notify = SIGEV_THREAD;
	cb.aio_sigevent.sigev_value.sival_ptr = (void *)&cb;
	cb.aio_sigevent.sigev_notify_function = notify_func;
	cb.aio_sigevent.sigev_notify_attributes = NULL;
	aio_read(&cb);
	
	sleep(3);

	free((void *)cb.aio_buf);
	close(fd);
	return 0;
}

Demo5,使用指定线程等待IO完成信号(目前不支持)

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <aio.h>
#include <pthread.h>

pid_t thread_tid;

pid_t gettid()
{
	return syscall(SYS_gettid);
}

void *thread_main(void *data)
{
	siginfo_t info = {};
	struct aiocb *cbp;

	thread_tid = gettid();
	sigwaitinfo((sigset_t *)data, &info);
	cbp = (struct aiocb *)info.si_ptr;
	if (aio_error(cbp))
	{
		perror("aio_error()");
	}
	else
	{
		printf("%s", (char *)cbp->aio_buf);
	}
	return 0;
}

int main(int argc, char *argv[])
{
	sigset_t set;

	pthread_attr_t attr;
	pthread_t thread_id;
	long thread_ret;

	int fd, ret;
	struct aiocb cb = {};

	if (argc < 2)
	{
		printf("Usage: %s <file>\n", argv[0]);
		return 1;
	}
	fd = open(argv[1], O_RDONLY);
	if (fd == -1)
	{
		perror("open()");
		return 1;
	}

	sigemptyset(&set);
	sigaddset(&set, SIGIO);
	pthread_sigmask(SIG_BLOCK, &set, NULL);

	pthread_attr_init(&attr);
	pthread_create(&thread_id, &attr, thread_main, (void *)&set);

	sleep(1);

	cb.aio_fildes = fd;
	cb.aio_lio_opcode = LIO_READ;
	cb.aio_buf = malloc(10241);
	cb.aio_nbytes = 10240;
	cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
	cb.aio_sigevent.sigev_signo = SIGIO;
	cb.aio_sigevent.sigev_value.sival_ptr = (void *)&cb;
	cb.aio_sigevent._sigev_un._tid = thread_tid;
	aio_read(&cb);

	pthread_join(thread_id, (void **)&thread_ret);
	pthread_attr_destroy(&attr);

	free((void *)cb.aio_buf);
	close(fd);
	return 0;
}

编译时需要添加库:rt, pthread

1, 发起AIO之后,可以使用 aio_suspend() 阻塞当前线程直到有IO完成;


2, 也可以使用信号通知,设置 struct aiocb 的 aio_sigevent.sigev_notify 为 SIGEV_SIGNAL;


3, 还可以使用新线程通知,设置 struct aiocb 的 aio_sigevent.sigev_notify 为 SIGEV_THREAD;


4, 未来还可能支持使用固定线程接收信号,设置 struct aiocb 的 aio_sigevent.sigev_notify 为 SIGEV_THREAD_ID (目前不可用,官方解释这个选项目前仅用于定时器)。