在我的 C++ 程序中,我使用该lio_listio
调用一次发送许多(最多几百个)写请求。之后,我做了一些计算,当我完成后,我需要等待所有未完成的请求完成,然后才能提交下一批请求。我怎样才能做到这一点?
现在,我只是aio_suspend
循环调用,每次调用一个请求,但这看起来很难看。看起来我应该使用struct sigevent *sevp
参数来lio_listio
. 我目前的猜测是我应该做这样的事情:
- 在主线程中,创建一个互斥锁并在调用
lio_listio
. - 在对 的调用中
lio_listio
,指定解锁此互斥锁的通知函数/信号处理程序。
这应该给我想要的行为,但它会可靠地工作吗?是否允许从信号处理程序上下文中操作互斥锁?我读到 pthread 互斥锁可以提供错误检测,并且如果您尝试从同一个线程再次锁定它们或从不同的线程解锁它们,则此解决方案依赖于死锁。
示例代码,使用信号处理程序:
void notify(int, siginfo_t *info, void *) {
pthread_mutex_unlock((pthread_mutex_t *) info->si_value);
}
void output() {
pthread_mutex_t iomutex = PTHREAD_MUTEX_INITIALIZER;
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_sigaction = ¬ify;
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &act, NULL);
for (...) {
pthread_mutex_lock(&iomutex);
// do some calculations here...
struct aiocb *cblist[];
int cbno;
// set up the aio request list - omitted
struct sigevent sev;
memset(&sev, 0, sizeof(struct sigevent));
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_ptr = &iomutex;
lio_listio(LIO_NOWAIT, cblist, cbno, &sev);
}
// ensure that the last queued operation completes
// before this function returns
pthread_mutex_lock(&iomutex);
pthread_mutex_unlock(&iomutex);
}
示例代码,使用通知功能 - 可能效率较低,因为创建了一个额外的线程:
void output() {
pthread_mutex_t iomutex = PTHREAD_MUTEX_INITIALIZER;
for (...) {
pthread_mutex_lock(&iomutex);
// do some calculations here...
struct aiocb *cblist[];
int cbno;
// set up the aio request list - omitted
struct sigevent sev;
memset(&sev, 0, sizeof(struct sigevent));
sev.sigev_notify = SIGEV_THREAD;
sev_sigev_notify_function = &pthread_mutex_unlock;
sev.sigev_value.sival_ptr = &iomutex;
lio_listio(LIO_NOWAIT, cblist, cbno, &sev);
}
// ensure that the last queued operation completes
// before this function returns
pthread_mutex_lock(&iomutex);
pthread_mutex_unlock(&iomutex);
}