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


    Because the compiler and the operating system are intimately involved with the execution of your code when you use SEH, I believe that the best way to demonstrate how SEH works is by examining source code samples and discussing the order in which the statements execute in each example.

    Therefore, the next few sections show different source code fragments, and the text associated with each fragment explains how the compiler and operating system alter the execution order of your code.

    因为在你使用SEH的时候,编译器和OS与你的代码执行密切相关,我认为展示SEH如何运作的最好的办法是分析例子中的执行顺序。
    因此,接下来的几个小节会展示不同的代码并解释编译器和OS是如何修改你的代码执行顺序。

    Funcenstein1

    To appreciate the ramifications of using termination handlers, let's examine a more concrete coding example:


    The numbered comments in the preceding code sample indicate the order in which your code will execute. In Funcenstein1, using the try-finally blocks isn't doing much for you. The code will wait for a semaphore, alter the contents of the protected data, save the new value in the local variable dwTemp, release the semaphore, and return the new value to the caller.

    上述例子中的数字标识了代码执行的顺序。在这个例子里,try、finally没有太大的帮助。这段代码会等待一个semaphore变为有信号,之后修改被保护的数据并保存在临时变量dwTemp中,释放semaphore,最后返回dwTemp。


    Funcenstein2

    Now let's modify the function a little and see what happens:


    In Funcenstein2, a return statement has been added to the end of the try block. This return statement tells the compiler that you want to exit the function and return the contents of the dwTemp variable, which now contains the value 5. However, if this return statement had been executed, the thread would not have released the semaphore—and no other thread would ever regain control of the semaphore. As you can imagine, this kind of sequence can become a really big problem because threads waiting for the semaphore might never resume execution.

    在本例中,try部分的末尾增加了一个return。这个return告诉编译器,你想从函数中退出并返回临时变量(值为5)。然而,如果这个语句被执行,这个线程将不会释放semaphore,这意味着,其他线程再也无法获得这个semaphore的控制权。你可以设想一下,这样做会造成严重的死锁。

    However, by using the termination handler, you have avoided the premature execution of the return statement. When the return statement attempts to exit the try block, the compiler makes sure that the code in the finally block executes first. The code inside the finally block is guaranteed to execute before the return statement in the try block is allowed to exit. In Funcenstein2, putting the call to ReleaseSemaphore into a termination handler block ensures that the semaphore will always be released. There is no chance for a thread to accidentally retain ownership of the semaphore, which would mean that all other threads waiting for the semaphore would never be scheduled CPU time.

    然后,借助termination hander,你可以避免这种过早的return。当return试图退出try代码块,编译器会确保finally中的代码先被执行。

    After the code in the finally block executes, the function does, in fact, return. Any code appearing below the finally block doesn't execute because the function returns in the try block. Therefore, this function returns the value 5, not the value 9.

    在finally中的代码执行后,这个函数返回了。finally下的代码没有被执行,因为函数在try代码块里return了。因此,这个函数返回5,而不是9.

    You might be asking yourself how the compiler guarantees that the finally block executes before the try block can be exited. When the compiler examines your source code, it sees that you have coded a return statement inside a try block. Having seen this, the compiler generates code to save the return value (5 in our example) in a temporary variable created by the compiler. The compiler then generates code to execute the instructions contained inside the finally block; this is called alocal unwind. More specifically, a local unwind occurs when the system executes the contents of a finally block because of the premature exit of code in a try block. After the instructions inside the finally block execute, the value in the compiler's temporary variable is retrieved and returned from the function.

    你也许会问,编译器是怎么保证finally中的代码在try退出前被执行。当编译器检视你的代码,发现在try的尾部有一个return的时候,它会创建一个临时变量保存值5。然后产生执行finally中代码的指令,这被称为a local unwind。

    As you can see, the compiler must generate additional code and the system must perform additional work to pull this whole thing off. On different CPUs, the steps needed for termination handling to work vary. You should avoid writing code that causes premature exits from the try block of a termination handler because the performance of your application could be adversely impacted. Later in this chapter, I'll discuss the__leave keyword, which can help you avoid writing code that forces local unwinds.

    你可以看到,为了搞定整件事,编译器必须产生额外的代码,同时系统必须执行额外的操作。在不同的CPU上,执行termination handing的步骤有所不同。你应该避免这种在try中提前退出,因为这样性能会受到一定影响。在本章稍后,我会谈一下关键字_leave,它可以帮助你避免写出会造成local unwinds的代码。

    Exception handling is designed to capture exceptions—the exceptions to the rule that you expect to happen infrequently (in our example, the premature return). If a situation is the norm, checking for the situation explicitly is much more efficient than relying on the SEH capabilities of the operating system and your compiler to trap common occurrences.

    Exception handing的设计初衷是捕获异常。异常是你希望很少出现的情况。如果某个情况是常态,那么显式检查该情况要比使用SEH有效得多。

    Note that when the flow of control naturally leaves the try block and enters the finally block (as shown in Funcenstein1), the overhead of entering the finally block is minimal. On x86 CPUs using Microsoft's compiler, a single machine instruction is executed as execution leaves the try block to enter the finally block—I doubt that you will even notice this overhead in your application. When the compiler has to generate additional code and the system has to perform additional work, as inFuncenstein2, the overhead is much more noticeable.

    注意,当程序自然地离开try,进入finally时,进入finally的overhead是最小的。如果是x86 CPU,使用微软的编译器,离开try进入finally只需要一条指令,你可能根本注意不到这其中的overhead。但是如果是本例的情况,overhead会明显得多。

    Funcenstein3

    Now let's modify the function again and take a look at what happens


    In Funcenstein3, when the compiler sees the goto statement in the try block, it generates a local unwind to execute the contents of the finally block first. However, this time, after the code in the finally block executes, the code after the ReturnValue label is executed because no return occurs in either the try or finally block. This code causes the function to return a 5. Again, because you have interrupted the natural flow of control from the try block into the finally block, you could incur a high performance penalty depending on the CPU your application is running on.

    在本例中当编译器在try中看到goto,它产生了一个local unwind来先执行finally里的内容。然后,这次,在finally中的代码被执行后,标签ReturnValue后的代码被执行,因为try和finally里都没有return。最终该函数返回5.同时,由于打乱了自然流程,你会付出高昂的性能开销。

  • 相关阅读:
    项目总结-驱虫市场电商数据挖掘
    电商数据处理项目
    Hive sql常用函数公式整理
    拉勾网‘数据分析师’职位招聘信息数据爬取
    鸢尾花数据(PCA主成分分析)
    项目总结-信用评分卡
    某保险公司参保客户分析
    Excel自定义格式参数
    VS2013创建ADO实体模型报:Microsoft.SqlServer.Management.Sdk.Sfc, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
    AngularJS-学习
  • 原文地址:https://www.cnblogs.com/zz962/p/2209707.html
Copyright © 2020-2023  润新知