About windows core programming series, structured exception handling, seh _ finally termination handling

Source: Internet
Author: User

Structured exception handling seh :__ finally termination processing.

 

Structuredexception handling is short for Seh. Is an exception handling mechanism provided by windows. One of the key reasons windows promotes seh to be added to Windows systems is that it can simplify the development of the operating system and make the system more robust.

We can also add the seh mechanism to our program, so that our application can become more robust. With Seh, we can focus on the normal workflow of the software when writing code. That is to say, the main functions of the software and the software exception handling tasks are separated, and finally the software may encounter various errors.

To implement Seh, the compiler has done a lot of work. When entering and leaving the exception handling code, the compiler inserts some additional code, which sometimes leads to great overhead. In the subsequent articles, I will introduce what the compiler has done.

Although different vendors implement seh in different ways, most compilation vendors follow Microsoft's syntax rules. Therefore, we will introduce the syntax stipulated by Microsoft VisualC ++ compiler.

Seh includes two aspects: Termination and exception handling. This article describes how to terminate processing, and the next article describes how to handle exceptions.

 

Termination handling

Terminate the processing program to ensure that the termination processing program can be executed no matter how the code block exits. The syntax is as follows:

_ Try {// protected code .} _ Finally // terminate the processing. {// Terminate the processing code .}

Note: Try and finally have two underscores.

The termination program is divided into two parts: __try block is the code to be protected by the abort handler. No matter how the program exits from the block (such as return and goto statements), __finally the block will be executed.

The _ Finally block is the termination handler block. The code in this block is called after the control flow exits from the _ Try block and before the program ends. It is generally used to perform cleanup operations, such as releasing resources and releasing mutex shares.

However, the "whatever method" mentioned above is absolute. Because there is no such thing in this world. When exitprocess, exitthread, terminateprocess, and terminatethread are used in the try block to terminate the thread or process, the Finally block will not be called. Pay special attention to these exceptions. Do not use these functions in the try block.

The following code is used to explain how to terminate the processing program:

__try{    WaitForSingleObject(hMutex,INFINITE);    if(x==false)       return-1;}__finally{          ReleaseMutex(hMutex);      return -2;}return 0;

We can see that the above Code first waits for the mutex volume kernel object to be triggered in try. After the wait is successful, the mutex volume belongs to the thread. If return-1 is executed at this time, the thread ends and the mutex object remains occupied. Other threads remain in the waiting state. This is the so-called resource leakage. With the Finally block protection, when the return-1 program tries to exit the try block, the compiler will let the Finally block be executed before return, and at the same time in the return (Other statements, such as the GOTO statement) insert some code before the statement. The return value is saved in a temporary variable.

But what is the return value of the Code Program above? Is it-1 or-2? The answer is-2. When the compiler detects the return statement in the try block, some code is generated to save the return value in a temporary variable. However, because the finally Block Code also has a return, the return value in the Finally block overwrites the original return value. Therefore, the function returns-2.

This process is called local expansion. Partial expansion occurs when the system exits early because of the Code in the try block. Local expansion can cause a very large extra cost, because the compiler must insert Code to ensure that the Finally block is executed before the program exits. The ideal situation is that the code control flow normally enters the Finally block by leaving the try block, and the additional overhead is minimized. In the x86 system, only one command is required to exit the try block and normally enter the Finally block.

To minimize performance overhead, we have improved the above Code:

_ Try {waitforsingleobject (hmutex, infinite); If (x = false) gotoendoftryblock; // some code. Endoftryblock :}__ finally {releasemutex (hmutex); Return-2;} return 0;

In the improved code above, when an error is detected in the try block, return is not directly called to force exit. Instead, a GOTO statement is executed to the end of the try block. After this jump is executed, the control flow Exits normally from the try block and directly enters the Finally block. Because no local expansion occurs, the compiler does not need to insert additional commands, which will not cause additional overhead.

 

Since the GOTO statement will destroy the execution process of the program, many books have repeatedly stressed that the use of goto is prohibited. In fact, we do not need to use Goto, because Microsoft provides us with a keyword _ leave, which can also perform similar operations. Keyword _ leave will cause the code execution control flow to jump to the end of the try block, so that the Code will normally enter the Finally block from the try block.

The following is the improved code using the _ leave Keyword:

_ Try {waitforsingleobject (hmutex, infinite); If (x = false) _ leave // some code .} _ Finally {releasemutex (hmutex); Return-2;} return 0;

At the beginning of this chapter, we have introduced the use of seh to enable programmers to separate normal execution processes from error handling. Here are two examples: one is not using Seh, and the other is using Seh. we can better understand how seh completes the above work by comparing them.

The following is a program that does not use seh:

Bool fun (char * filename) {handlehfile = createfile (....); if (hfile = invalid_handle_value) {returnfalse;} handlehfilemapping = createfilemapping (...); if (hfile = NULL) {closehandle (hfile); returnfalse;} Char * P = mapviewoffile (..); if (P = NULL) {closehandle (hfile); closehandle (hfilemapping); Return false ;}// other work ....... returntrue ;}

 

I believe many of us have written code similar to the above. We can see that the above Code contains a lot of error checking and resource clearing code. Too many error code checks and resource cleanup tasks make the code difficult to read and write, modify, and maintain.

Now let's use the seh mechanism to improve the above Code:

Bool fun (char * filename) {handlehfile = invalid_handle_value; handlehfilemapping = NULL; char * P = NULL; _ Try {hfile = createfile (....); if (hfile = invalid_handle_value) _ leave; hfilemapping = createfilemapping (...); if (hfile = NULL) _ leave; P = mapviewoffile (..); if (P = NULL) _ leave; // other code. } _ Finally {If (hfile! = Invalid_handle_value) closehandle (hfile); If (hfilemapping) closehandle (hfilemapping);} returntrue ;}

From the above code, we can see that the code is much more concise. The cleanup work is put at the end of execution, and can be ensured to be executed. The code looks concise and orderly, improving readability is also conducive to future maintenance.

Note: We have introduced two scenarios that will cause finally block execution:

1. Exit from the try block normally and enter the Finally block.

2. Partial expansion: Exit from the try block in advance and forcibly transfer the program control flow to the Finally block.

In addition to the preceding situation, a global expansion also causes finally blocks to be executed. For details about global expansion related to exception handling, we will introduce it in the next article!

Finally execution is caused by one of the three cases above.

If you want to determine whether to log on to finally normally or exit the try block abnormally, you can call the abnormaltermination function to determine whether to exit:

BOOL AbnormalTermination();


Note that this function can only be called in the Finally block. If true is returned, the control flow is normally entered into the Finally block from the try block. If false is returned, the control flow exits abnormally from the try block. This is usually caused by executing the Goto, break, return, or continue statement, or the code in the try block throws an exception and causes global expansion.


If any, please correct me! Thank you!

2013, 3, and 11 in Hangzhou, Zhejiang Province

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.