Scroll to navigation

AIO(7) Miscellaneous Information Manual AIO(7)

الاسم

aio - نظرة عامة على الإدخال/الإخراج غير المتزامن وفق معيار POSIX

الوصف

واجهة الإدخال/الإخراج غير المتزامن (AIO) وفق معيار POSIX تسمح للتطبيقات ببدء عملية إدخال/إخراج واحدة أو أكثر تُنفذ بشكل غير متزامن (أي في الخلفية). يمكن للتطبيق اختيار الإشعار بإتمام عملية الإدخال/الإخراج بطرق متنوعة: عبر تسليم إشارة، أو عبر إنشاء خيط، أو بدون أي إشعار على الإطلاق.

تتكون واجهة POSIX AIO من الدوال التالية:

aio_read(3)
إدراج طلب قراءة في قائمة الانتظار. هذا هو النظير غير المتزامن لـ read(2).
aio_write(3)
إدراج طلب كتابة في قائمة الانتظار. هذا هو النظير غير المتزامن لـ write(2).
aio_fsync(3)
إدراج طلب مزامنة لعمليات الإدخال/الإخراج على واصف ملف. هذا هو النظير غير المتزامن لـ fsync(2) و fdatasync(2).
aio_error(3)
الحصول على حالة الخطأ لطلب إدخال/إخراج مُدرج في قائمة الانتظار.
aio_return(3)
الحصول على حالة الإرجاع لطلب إدخال/إخراج مُكتمل.
aio_suspend(3)
تعليق المستدعي حتى اكتمال طلب إدخال/إخراج واحد أو أكثر من مجموعة محددة.
aio_cancel(3)
محاولة إلغاء طلبات الإدخال/الإخراج المعلقة على واصف ملف محدد.
lio_listio(3)
إدراج طلبات إدخال/إخراج متعددة في قائمة الانتظار باستخدام استدعاء دالة واحد.

هيكل aiocb ("كتلة التحكم في الإدخال/الإخراج غير المتزامن") يُعرّف المعاملات التي تتحكم في عملية إدخال/إخراج. يُستخدم وسيط من هذا النوع مع جميع الدوال المذكورة أعلاه. هذا الهيكل له الشكل التالي:


#include <aiocb.h>
struct aiocb {

/* The order of these fields is implementation-dependent */
int aio_fildes; /* File descriptor */
off_t aio_offset; /* File offset */
volatile void *aio_buf; /* Location of buffer */
size_t aio_nbytes; /* Length of transfer */
int aio_reqprio; /* Request priority */
struct sigevent aio_sigevent; /* Notification method */
int aio_lio_opcode; /* Operation to be performed;
lio_listio() only */
/* Various implementation-internal fields not shown */ }; /* Operation codes for 'aio_lio_opcode': */ enum { LIO_READ, LIO_WRITE, LIO_NOP };

حقول هذا الهيكل هي كالتالي:

واصف الملف الذي سيجري عليه الإدخال/الإخراج.
هذه هي إزاحة الملف التي ستُجرى عندها عملية الإدخال/الإخراج.
هذه هي الخبيئة المستخدمة لنقل البيانات لعملية قراءة أو كتابة.
هذا هو حجم الوسيط الذي يشير إليه aio_buf.
يحدد هذا الحقل قيمة تُطرح من أولوية الوقت الفعلي للخيط المستدعي لتحديد أولوية تنفيذ طلب الإدخال/الإخراج هذا (انظر pthread_setschedparam(3)). يجب أن تكون القيمة المحددة بين 0 والقيمة التي يُرجعها sysconf(_SC_AIO_PRIO_DELTA_MAX). يُتجاهل هذا الحقل لعمليات مزامنة الملف.
هذا الحقل هو هيكل يحدد كيفية إشعار المستدعي عند اكتمال عملية الإدخال/الإخراج غير المتزامن. القيم الممكنة لـ aio_sigevent.sigev_notify هي SIGEV_NONE و SIGEV_SIGNAL و SIGEV_THREAD. انظر sigevent(3type) لمزيد من التفاصيل.
نوع العملية المراد تنفيذها؛ يُستخدم فقط لـ lio_listio(3).

بالإضافة إلى الدوال القياسية المذكورة أعلاه، توفر مكتبة GNU C الامتداد التالي لواجهة برمجة تطبيقات POSIX AIO:

aio_init(3)
ضبط المعاملات لضبط سلوك تطبيق glibc POSIX AIO.

الأخطاء

حقل aio_reqprio في بنية aiocb كان أقل من 0، أو أكبر من الحد الذي أعادته استدعاء sysconf(_SC_AIO_PRIO_DELTA_MAX).

المعايير

POSIX.1-2008.

التاريخ

POSIX.1-2001. glibc 2.1.

ملاحظات

من الجيد تصفير مخزن كتلة التحكم قبل الاستخدام (انظر memset(3)). لا يجب تغيير مخزن كتلة التحكم والمخزن المشار إليه بواسطة aio_buf أثناء تنفيذ عملية الإدخال/الإخراج. يجب أن تظل هذه المخازن صالحة حتى اكتمال عملية الإدخال/الإخراج.

عمليات القراءة أو الكتابة غير المتزامنة المتزامنة باستخدام نفس بنية aiocb تنتج نتائج غير محددة.

تطبيق Linux POSIX AIO الحالي يُقدم في مساحة المستخدم بواسطة glibc. هذا له عدد من القيود، أبرزها أن الحفاظ على خيوط متعددة لتنفيذ عمليات الإدخال/الإخراج مكلف ويواجه صعوبة في التوسع. العمل جارٍ منذ بعض الوقت على تطبيق قائم على آلة حالة النواة للإدخال/الإخراج غير المتزامن (انظر io_submit(2)، io_setup(2)، io_cancel(2)، io_destroy(2)، io_getevents(2))، لكن هذا التطبيق لم ينضج بعد إلى النقطة التي يمكن فيها إعادة تطبيق POSIX AIO بالكامل باستخدام استدعاءات نظام النواة.

أمثلة

البرنامج أدناه يفتح كل ملف مسمى في وسائط سطر الأوامر ويصطف طلبًا على واصف الملف الناتج باستخدام aio_read(3). ثم يتكرر البرنامج، مراقبًا دوريًا كل عملية إدخال/إخراج لا تزال قيد التنفيذ باستخدام aio_error(3). كل طلب إدخال/إخراج يُعد لتوفير إشعار عن طريق تسليم إشارة. بعد اكتمال جميع طلبات الإدخال/الإخراج، يسترجع البرنامج حالتها باستخدام 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 <err.h>
#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     /* Size of buffers for read operations */
struct ioRequest {      /* Application-defined structure for tracking

I/O requests */
int reqNum;
int status;
struct aiocb *aiocbp; }; static volatile sig_atomic_t gotSIGQUIT = 0;
/* On delivery of SIGQUIT, we attempt to
cancel all outstanding I/O requests */ static void /* Handler for SIGQUIT */ quitHandler(int sig) {
gotSIGQUIT = 1; } #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ static void /* Handler for I/O completion signal */ aioSigHandler(int sig, siginfo_t *si, void *ucontext) {
if (si->si_code == SI_ASYNCIO) {
write(STDOUT_FILENO, "I/O completion signal received\n", 31);
/* The corresponding ioRequest structure would be available as
struct ioRequest *ioReq = si->si_value.sival_ptr;
and the file descriptor would then be available via
ioReq->aiocbp->aio_fildes */
} } int main(int argc, char *argv[]) {
struct sigaction sa;
int s;
int numReqs; /* Total number of queued I/O requests */
int openReqs; /* Number of I/O requests still in progress */
if (argc < 2) {
fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",
argv[0]);
exit(EXIT_FAILURE);
}
numReqs = argc - 1;
/* Allocate our arrays. */
struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList));
if (ioList == NULL)
err(EXIT_FAILURE, "calloc");
struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList));
if (aiocbList == NULL)
err(EXIT_FAILURE, "calloc");
/* Establish handlers for SIGQUIT and the I/O completion signal. */
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sa.sa_handler = quitHandler;
if (sigaction(SIGQUIT, &sa, NULL) == -1)
err(EXIT_FAILURE, "sigaction");
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sa.sa_sigaction = aioSigHandler;
if (sigaction(IO_SIGNAL, &sa, NULL) == -1)
err(EXIT_FAILURE, "sigaction");
/* Open each file specified on the command line, and queue
a read request on the resulting file descriptor. */
for (size_t 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)
err(EXIT_FAILURE, "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)
err(EXIT_FAILURE, "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)
err(EXIT_FAILURE, "aio_read");
}
openReqs = numReqs;
/* Loop, monitoring status of I/O requests. */
while (openReqs > 0) {
sleep(3); /* Delay between each monitoring step */
if (gotSIGQUIT) {
/* On receipt of SIGQUIT, attempt to cancel each of the
outstanding I/O requests, and display status returned
from the cancelation requests. */
printf("got SIGQUIT; canceling I/O requests: \n");
for (size_t j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" Request %zu 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
perror("aio_cancel");
}
}
gotSIGQUIT = 0;
}
/* Check the status of each I/O request that is still
in progress. */
printf("aio_error():\n");
for (size_t j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" for request %zu (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:
perror("aio_error");
break;
}
if (ioList[j].status != EINPROGRESS)
openReqs--;
}
}
}
printf("All I/O requests completed\n");
/* Check status return of all I/O requests. */
printf("aio_return():\n");
for (size_t j = 0; j < numReqs; j++) {
ssize_t s;
s = aio_return(ioList[j].aiocbp);
printf(" for request %zu (descriptor %d): %zd\n",
j, ioList[j].aiocbp->aio_fildes, s);
}
exit(EXIT_SUCCESS); }

انظر أيضًا

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)

”دعم عمليات الإدخال/الإخراج غير المتزامنة في لينكس 2.5“، باتشاريا، برات، بولافارتي، ومورغان، وقائع ندوة لينكس، 2003، https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf

ترجمة

تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.

8 فبراير 2026 صفحات دليل لينكس 6.18