Windows core programming uses thread APC callback to safely exit multiple waiting threads

Source: Internet
Author: User
Tags apc

Preface

These situations are often encountered in program development: The worker thread is waiting for the kernel object to fire, and the main thread needs to force the worker to terminate. What we often do is use: TerminateThread to force the termination of the thread. This is certainly not a good thing, the system will not destroy the stack of this thread after forcing the thread to terminate, and the memory leak will be a serious problem for a long time. The safest way to exit a thread is, of course, to return it. This article focuses on a secure exit thread approach described in Windows core programming: Use the wait API to wait for a kernel object to fire, add a thread APC callback.

API Introduction

The first step is to introduce the next important Windows API

DWORD WINAPI QUEUEUSERAPC (  __in          pfnapc,  __in hthread          ,  __in          dwdata );

function allows us to manually add an APC callback to the specified thread queue, callback function: VOID WINAPI ApcCallback1 (ulong_ptr dwparam)
This thread can be any thread in the system, and if the identified thread is in another process, then the address of the callback function must also be in the address space of the other thread.
QUEUEUSERAPC can also be used to force a thread to exit the wait state, and when the thread is waiting for a kernel object to fire, it can use it to force wake the waiting thread and let it kill itself.

In addition , Windows provides 6 APIs to set the state of a thread to a reminder state.

SleepEx (
__in DWORD dwmilliseconds,
__in BOOL balertable
);
WaitForSingleObjectEx (
__in HANDLE Hhandle,
__in DWORD dwmilliseconds,
__in BOOL balertable
);
WaitForMultipleObjectsEx (
__in DWORD ncount,
__in_ecount (ncount) CONST HANDLE *lphandles,
__in BOOL bWaitAll,
__in DWORD dwmilliseconds,
__in BOOL balertable
);
SignalObjectAndWait (
__in HANDLE hobjecttosignal,
__in HANDLE Hobjecttowaiton,
__in DWORD dwmilliseconds,
__in BOOL balertable
);
Getqueuedcompletionstatusex
Msgwaitformultipleobjectsex using mwmo_alertable to identify threads into a waiting state
The old version of the five functions API, that is, without ex in the internal implementation is called the corresponding ex function, passed into the balertable=false.

The calls to these functions and the completion callback, APC callbacks are described in detail in the alerting I/O, which is omitted for the time being.

Instance Code

Mark the last index value for each thread volatile longg_nindex = 0; UINT __stdcall Thread1 (void* lpparam) {//Use atomic lock to operate thread synchronization in user mode, faster long Lprevindex = InterlockedExchangeAdd (&g_ NIndex, 1);//We need to record the original value long lcurindex= Lprevindex + 1;cout<< "thread" <<lCurIndex<< "Start Execution" <<endl; while (true) {//cout<< "Thread1:" <<nindex<<endl;//sleeps for one second, the thread enters the alert state if (wait_io_completion = = SleepEx (+, TRUE)) {//At this point, we add an item to the APC queue and the thread can exit the break;} nindex++;} cout<< "Thread" <<lCurIndex<< "normal exit" <<endl;return 0; APC callback function void WINAPI apccallback (ulong_ptr dwparam) {//Because just so that the thread exits gracefully immediately without having to kill the thread, we can do nothing here cout<< " Apccallback: The APC callback function of the thread executes "&LT;&LT;ENDL;} BOOL Apctest () {const int nthreadcount = 10; HANDLE Hthread[nthreadcount];int i = 0;  for (int i=0; i<nthreadcount; ++i) hthread[i] = (HANDLE) _beginthreadex (null, 0, Thread1, NULL, 0, NULL);D word dwerror, Dwret;while (true) {Dwret = WaitForMultipleObjects (Nthreadcount, Hthread, True, 10*1000); if (Dwret = = wait_timeout) {//etc To timeout, try to force the termination of the thread//Because the worker thread sleeps when it enters the waiting state, manually adding callbacks to the APC queue will result in the destruction of the thread emptying queue after execution, the thread exits the alert state//At this time, the thread exits amicably. for (i=0; i<nthreadcount; ++i) {dwret = QUEUEUSERAPC (Apccallback, Hthread[i], if (Dwret = = 0) {//Add APC callback to thread APC team Column Failed dwerror = GetLastError (); break;}} Continue;} if (wait_object_0 = = Dwret) {cout<< "worker thread has exited, loop exited ..." <<endl;break;} for (i=0; i<nthreadcount; ++i) CloseHandle (Hthread[i]); return true;}

Program run


Summary

The main thing is to use those extended APIs (with ex) to get threads into a waiting state when the thread waits. At this point, the system checks the APC queue of the thread first. Because we have added a callback function to the APC queue of the thread, the queue is not empty, the APC function is called, and the queue is emptied. Then the function executes and returns to Wait_io_completion, when we know that we have added an APC callback and booted the thread to exit itself. This enables multiple waiting threads to safely exit the wait state.

Windows core programming uses thread APC callback to safely exit multiple waiting threads

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.