Alertable Io provides a more effective asynchronous notification format. Readfileex/writefileex provides a callback function (APC process) when sending an IO request. After the IO request is complete, the callback function will be executed once the thread enters the alarming status.
The following five functions enable the thread to enter the alarm status:
Sleepex
Waitforsingleobjectex
Waitformultipleobjectsex
Signalobjectandwait
Msgwaitformultipleobjectsex
When a thread enters the alarm state, the kernel will check the APC queue of the thread. If the queue contains APC, It will be executed in FIFO order. If the queue is empty, the thread suspends the waiting event object. At a certain time point in the future, once the APC enters the queue, the thread will be awakened to execute the APC and wait for the function to return wait_io_completion.
Queueuserapc can be used to deliver APC manually. The APC can be executed as long as the target thread is in the alarm state.
The main disadvantage of using alarm Io is that the thread sending the IO request must also be the thread processing the result. If there is still an unfinished Io request when a thread exits, the application will lose the IO completion notification forever. However, we will see that there is no such restriction on the I/O finished port.
The following code demonstrates the usage of queueuserapc.
/*************************************** *********************************/
/* APC test .*/
/*************************************** *********************************/
DWORD winapi workthread (pvoid pparam)
{
Handle event = (handle) pparam;
For (;;)
{
DWORD dwret = waitforsingleobjectex (event, infinite, true );
If (dwret = wait_object_0)
Break;
Else if (dwret = wait_io_completion)
Printf ("wait_io_completion/N ");
}
Return 0;
}
Void callback apcproc (DWORD dwparam)
{
Printf ("% s", (pvoid) dwparam );
}
Void testapc (bool bfast)
{
Handle quitevent = createevent (null, false, false, null );
Handle hthread = createthread (null,
0,
Workthread,
(Pvoid) quitevent,
0,
Null );
Sleep (100); // wait for workthread initialized.
For (INT I = 5; I> 0; I --)
{
Queueuserapc (apcproc, hthread, (DWORD) (pvoid) "APC here/N ");
If (! Bfast)
Sleep (1000 );
}
Setevent (quitevent );
Waitforsingleobject (hthread, infinite );
Closehandle (hthread );
}