`
sony-soft
  • 浏览: 1021780 次
文章分类
社区版块
存档分类
最新评论

Chapter 23: Termination Handlers(2)Understanding Termination Handlers by Example(2)

 
阅读更多

Funcfurter1

Now let's look at another scenario in which termination handling really proves its value. Look at this function:

DWORD Funcfurter1() {
   DWORD dwTemp;

   // 1. Do any processing here.
   ...
   __try {
      // 2. Request permission to access
      //    protected data, and then use it.
      WaitForSingleObject(g_hSem, INFINITE);

      dwTemp = Funcinator(g_dwProtectedData);
   }
   __finally {
      // 3. Allow others to use protected data.
      ReleaseSemaphore(g_hSem, 1, NULL);
   }

   // 4. Continue processing.
   return(dwTemp);
}

Now imagine that the Funcinator function called in the try block contains a bug that causes an invalid memory access. Without SEH, this situation would present the user with the ever-popular "Application has stopped working" dialog box provided by theWindows Error Reporting (WER) that will be presented in great detail inChapter 25, "Unhandled Exceptions, Vectored Exception Handling, and C++ Exceptions." When the user dismissed the error dialog box, the process would be terminated. When the process is terminated (because of an invalid memory access), the semaphore would still be owned and would never be released—any threads in other processes that were waiting for this semaphore would never be scheduled CPU time. But placing the call toReleaseSemaphore in afinally block guarantees that the semaphore gets released even if some other function causes a memory access violation. I have to put a damper on this statement: starting with Windows Vista, you have to explicitly protect your try/finally to ensure that thefinally block gets executed when an exception is raised. The necessary explanations are provided in "The SEH Termination Sample Application" on page 673, and the next chapter will dig into the details of thetry/except protection.

现在设想一下,在本例中的函数Funcinator中有一个bug,会产生非法内存访问。如果不使用SEH,这种形势下,会出现一个WER提供的错误报告对话框(在25章里详细讲解)。如果用户关闭这个对话框,该进程将被终止,此时semaphore没有被释放,等待它的线程将继续等待。但把ReleaseSemaphore放到finally里,会保证semaphore会被正确释放,即使其他函数导致了内存访问冲突。(似从Vista开始)

However, even in prior versions of Windows, the finally blocks are not guaranteed to execute for any exception. For example, in Windows XP, if a stack exhaustion exception occurs in thetry block, chances are good that thefinally block is not going to get executed, because the WER code is running inside the faulting process possibly without enough stack left to report an error, so the process would be silently terminated. Similarly, if the exception generated a corruption in the SEH chain, the termination handler will not be executed. Last but not least, if another exception happened in the exception filter, the termination handler will not get executed. The rule of thumb to follow is always minimize the action of the code that runs withincatch orfinally blocks; otherwise, the process just terminates and no morefinally blocks execute. This is why the error reporting in Windows Vista runs in a separate process, as detailed inChapter 25.

然而,在以前的Windows中,finally块并不能保证对任何异常都能执行。比如,在XP里,try中的堆栈异常不会导致finally中的代码被执行,因为WER代码在出错的进程里执行,很可能没有足够的stack来报告错误,因此进程会悄然结束。类似的,如果在SEH链中,异常产生了一个冲突,termination hander不会被执行。Last but not least,如果在exception filter中发生了其他异常,termination hander不会被执行。The rule of thumb to follow is always minimize the action of the code that runs withincatchorfinallyblocks; otherwise, the process just terminates and no morefinallyblocks execute. This is why the error reporting in Windows Vista runs in a separate process, as detailed inChapter 25.

If termination handlers are powerful enough to capture a process while terminating because of an invalid memory access, we should have no trouble believing that they will also capturesetjump andlongjump combinations and, of course, simple statements such asbreak andcontinue.

如果 termination handers很强大,可以捕获因为非法内存访问终止的进程,we should have no trouble believing that they will also capture setjump and longjump combinations and, of course, simple statements such as break and continue.


Pop Quiz Time: FuncaDoodleDoo

Now for a test. Can you determine what the following function returns?

DWORD FuncaDoodleDoo() {
   DWORD dwTemp = 0;

   while (dwTemp < 10) {

      __try {
         if (dwTemp == 2)
            continue;

         if (dwTemp == 3)
            break;
      }
      __finally {
         dwTemp++;
      }

      dwTemp++;
   }

   dwTemp += 10;
   return(dwTemp);
}

Let's analyze what the function does step by step. First dwTemp is set to 0. The code in the try block executes, but neither of the if statements evaluates to TRUE. Execution moves naturally to the code in thefinally block, which incrementsdwTemp to1. Then the instruction after thefinally block incrementsdwTemp again, making it2.

一步步分析一下这个函数。首先 dwTemp为0,进入try之后,因为没有一个if为TRUE,执行流程自然地进入finally块,在这里dwTemp被自增。finally后的代码再次自增,使之为2

When the loop iterates, dwTemp is 2 and the continue statement in the try block will execute. Without a termination handler to force execution of thefinally block before exit from thetry block, execution would immediately jump back up to thewhile test,dwTemp would not be changed, and we would have started an infinite loop. With a termination handler, the system notes that thecontinue statement causes the flow of control to exit thetry block prematurely and moves execution to thefinally block. In thefinally block,dwTemp is incremented to3. However, the code after thefinally block doesn't execute because the flow of control moves back tocontinue and thus to the top of the loop.

在接下来的循环中,由于dwTemp为2,try中的continue将被执行。Without a termination handler to force execution of thefinallyblock before exit from thetryblock,执行流程将立即回到while,dwTemp将永远不变,程序将陷入死循环。借助termination hander,系统会注意到continue将导致有提前退出try的情况并执行finally。在finally里,dwTemp被自增到3,然后,finally后的代码此次将不被执行,因为流程跳回到continue,继续循环。

Now we are processing the loop's third iteration. This time, the firstif statement evaluates toFALSE, but the secondif statement evaluates toTRUE. The system again catches our attempt to break out of thetry block and executes the code in thefinally block first. NowdwTemp is incremented to4. Because abreak statement was executed, control resumes after the loop. Thus, the code after thefinally block and still inside the loop doesn't execute. The code below the loop adds10 todwTemp for a grand total of14—the result of calling this function. It should go without saying that you should never actually write code likeFuncaDoodleDoo. I placed thecontinue andbreak statements in the middle of the code only to demonstrate the operation of the termination handler.

现在我们执行第三次循环。这次,第二个if被满足,系统再次发现我们要提前退出try,因此先执行finally。现在dwTemp被自增到4.因为执行的是break,finally中的代码还是没有被执行,循环底下的代码被执行,最后的结果变为14.

Although a termination handler will catch most situations in which thetry block would otherwise be exited prematurely, it can't cause the code in afinally block to be executed if the thread or process is terminated. A call toExitThread orExitProcess will immediately terminate thethread or process without executing any of the code in afinally block. Also, if your thread or process should die because some application calledTerminateThread orTerminateProcess, the code in afinally block again won't execute. Some C run-time functions (such asabort) that in turn callExitProcess again preclude the execution offinally blocks. You can't do anything to prevent another application from terminating one of your threads or processes, but you can prevent your own premature calls toExitThread andExitProcess.

如果进程或者线程是被ExitThread或者ExitProcess终止的,finally中的代码将不会执行。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics