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:

DWORD Funcenstein1() { DWORD dwTemp; // 1. Do any processing here. ... __try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData; } __finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); } // 4. Continue processing. return(dwTemp); }

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:

DWORD Funcenstein2() { DWORD dwTemp; // 1. Do any processing here. ... __try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData; // Return the new value. return(dwTemp); } __finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); } // Continue processing--this code // will never execute in this version. dwTemp = 9; return(dwTemp); }

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

DWORD Funcenstein3() { DWORD dwTemp; // 1. Do any processing here. ... __try { // 2. Request permission to access // protected data, and then use it. WaitForSingleObject(g_hSem, INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData; // Try to jump over the finally block. goto ReturnValue; } __finally { // 3. Allow others to use protected data. ReleaseSemaphore(g_hSem, 1, NULL); } dwTemp = 9; // 4. Continue processing. ReturnValue: return(dwTemp); }

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.同时,由于打乱了自然流程,你会付出高昂的性能开销。

转载于:https://www.cnblogs.com/zz962/archive/2011/10/09/2209707.html

数据治理是确保数据准确性、可靠性、安全性、可用性和完整性的体系和框架。它定义了组织内部如何使用、存储、保护和共享数据的规则和流程。数据治理的重要性随着数字化转型的加速而日益凸显,它能够提高决策效率、增强业务竞争力、降低风险,并促进业务创新。有效的数据治理体系可以确保数据在采集、存储、处理、共享和保护等环节的合规性和有效性。 数据质量管理是数据治理中的关键环节,它涉及数据质量评估、数据清洗、标准化和监控。高质量的数据能够提升业务决策的准确性,优化业务流程,并挖掘潜在的商业价值。随着大数据和人工智能技术的发展,数据质量管理在确保数据准确性和可靠性方面的作用愈发重要。企业需要建立完善的数据质量管理和校验机制,并通过数据清洗和标准化提高数据质量。 数据安全与隐私保护是数据治理中的另一个重要领域。随着数据量的快速增长和互联网技术的迅速发展,数据安全与隐私保护面临前所未有的挑战。企业需要加强数据安全与隐私保护的法律法规和技术手段,采用数据加密、脱敏和备份恢复等技术手段,以及加强培训和教育,提高安全意识和技能水平。 数据流程管理与监控是确保数据质量、提高数据利用率、保护数据安全的重要环节。有效的数据流程管理可以确保数据流程的合规性和高效性,而实时监控则有助于及时发现并解决潜在问题。企业需要设计合理的数据流程架构,制定详细的数据管理流程规范,并运用数据审计和可视化技术手段进行监控。 数据资产管理是将数据视为组织的重要资产,通过有效的管理和利用,为组织带来经济价值。数据资产管理涵盖数据的整个生命周期,包括数据的创建、存储、处理、共享、使用和保护。它面临的挑战包括数据量的快速增长、数据类型的多样化和数据更新的迅速性。组织需要建立完善的数据管理体系,提高数据处理和分析能力,以应对这些挑战。同时,数据资产的分类与评估、共享与使用规范也是数据资产管理的重要组成部分,需要制定合理的标准和规范,确保数据共享的安全性和隐私保护,以及建立合理的利益分配和权益保障机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值