Windows API learns to synchronize---threads with kernel objects

Source: Internet
Author: User
Tags mutex terminates

Objective

A number of kernel objects, including processes, threads, and jobs. All of these kernel objects can be used for synchronization purposes. For thread synchronization, each of these kernel objects can be said to be in a notified or non-notified state. The switchover of this state is determined by the set of rules that Microsoft establishes for each object. For example, a process kernel object is always created in the non-notification state. When the process terminates, the operating system automatically causes the process's kernel object to be in a notified state. Once the process kernel object is notified, it will remain in this state forever, and its state will never change to an unspecified state.
When the process is running, the process kernel object is in an unnamed state, and when the process terminates, it becomes the notification state. The process kernel object is a Boolean value that is initialized to false (no notification state) when the object is created. When the process terminates running, the operating system automatically changes the corresponding object Boolean value to True, indicating that the object has been notified.
If you are writing code that checks whether a process is still running, you only need to call a function to let the operating system check the Boolean value of the Process object, which is very simple. You may also want to tell the system to put the thread into a wait state, and then automatically wake the thread when the Boolean value is from False to true. In this way, you can write a code in which the thread in the parent process that waits for the child process to terminate runs only needs to put itself to sleep until the kernel object that identifies the child process becomes the notification state. As you'll see, Microsoft Windows provides some functions that are very easy to do.
Just now. Microsoft has defined some rules for process kernel objects. In fact, thread kernel objects follow the same rules. That is, thread kernel objects are always created in the non-notification state. When a thread terminates running, the operating system automatically changes the state of the thread object to the notified state. Therefore, you can use the same method for your application to determine whether the thread is no longer running. Like a process kernel object, a thread kernel object can be in a notified or non-notified state. The following kernel objects can be in the notification State or in the non-notification state:
Process file Modification Notification
Thread Events
Job can wait timer

Document Beacons
Console input Mutex Object

A thread can put itself into a wait state until an object changes to a notification state. Note that the rules for controlling the notification/non-notification state of each object depend on the type of object. The rules of the process and thread objects and the rules of the job are mentioned earlier.
This chapter will describe the functions that allow threads to wait for a kernel object to become a notified state. Then we're going to talk about the various kernel objects, such as events, wait counters, beacons, and mutex objects, provided by the WI n d o w S, which are specifically designed to help implement thread synchronization.
When I first started to learn this, I imagined that the kernel object contained a banner (a flag flying in the air, not a drooping banner), which helped me. When the kernel object is notified, the banner rises, and when the object is not notified, the banner falls down (see Figure 9-1).
These threads are not dispatched when the thread waits for an object that is in the non-notification state (flag down). But once the object becomes a notification state (banner up), the thread sees the flag become scheduled and resumes running quickly (see Figure 9-2).

  

  

1 wait function

The wait function allows a thread to voluntarily enter a wait state until a particular kernel object becomes a notified state. The most common of these wait functions is WaitForSingleObject:

DWORD WaitForSingleObject (    HANDLE hobject,    DWORD dwmilliseconds);

When the thread calls the function, the first parameter, Hobject, identifies a kernel object that can support notification/non-notification (any of the objects listed earlier applies). The second parameter, dwmilliseconds, allows the thread to indicate how long it will wait in order to wait for the object to become a notified state.
Call the following function to tell the system that the calling function is ready to wait until the process identified by the hprocess handle terminates running:

WaitForSingleObject (hprocess, INFINITE);

The second parameter tells the system that the calling thread is willing to wait forever (infinite amount of time) until the process terminates.

Typically, infinite is passed as the second argument to WaitForSingleObject, but it can also pass any value (in milliseconds). By the way, infinite has been defined as 0xFFFFFFFF (or-1). Of course, passing infinite is a bit dangerous. If the object never becomes a notified state, then the calling thread will never wake up, and it'll always be in a deadlock state, but it will not waste valuable CPU time. Here's an example of how to call WaitForSingleObject with a timeout value instead of infinite:

DWORD DW = WaitForSingleObject (hprocess, the);Switch(DW) { CaseWAIT_OBJECT_0://The process terminated         Break;  Casewait_timeout://The process did not terminate within milliseconds         Break;  Casewait_failed://Bad call to function (invalid handle?)         Break;}

The above code tells the system that the calling thread should not become a scheduled state until a particular process terminates, or until the end of the 5000ms time. Therefore, if the process terminates, the function call will return in less than 5000ms of time, and if the process has not been terminated, it returns within approximately 5000ms time. Note that you cannot pass 0 for dwmilliseconds. If the 0,waitforsingleobject function is passed, it will always return immediately.
The return value of WaitForSingleObject can indicate why the calling thread has become a scheduled state again. If the thread waits for the object to become a notified state, the return value is WAIT_OBJECT_0. If the timeout set has expired, the return value is wait_timeout. If you pass an incorrect value (such as an invalid handle) to WaitForSingleObject, the return value will be wait_failed (to learn more, call GetLastError).
The following function, WaitForMultipleObjects, is similar to the WaitForSingleObject function, except that it allows the calling thread to view the notified state of several kernel objects at the same time:

DWORD WaitForMultipleObjects (    DWORD dwcount,    CONST HANDLE* phobjects,    BOOL fWaitAll,    DWORD dwmilliseconds);

The dwcounts parameter is used to indicate the number of kernel objects that you want the function to view. This value must be between 1 and maximum_waitobjects (defined as 64 in the Windows header file). The phobjects parameter is a pointer to an array of kernel object handles.

You can use the WaitForMultipleObjects function in two different ways. One way is to have the thread go into a wait state until any one of the specified kernel objects becomes a notified state. Another way is to get the thread to wait until all the specified kernel objects become notified. The fWaitAll parameter tells the function how you want it to be used. If true is passed for this parameter, the function will not allow the calling thread to run until all the objects become notified states.

The function of the dwmilliseconds parameter is exactly the same as it does in WA WaitForSingleObject. If the specified time is reached while waiting, the function will return anyway. Again, it is common to pass infinite for this parameter, but you should be careful when writing code to avoid deadlock situations.
The return value of the WaitForMultipleObjects function tells the calling thread why it is being re-dispatched. The possible return values are wait_failed and wait_timeout, and the effect of these two values is clear. If true is passed for the fWaitAll parameter and all objects become notification states, the return value is WAIT_OBJECT_0. If False is passed for fWaitAll, the function returns once any one of the objects becomes a notified state. In this case, you may want to know which object becomes the notification state. The return value is a value between Wait_object_0 and (Wait_object_0 + dwCount-1). In other words, if the return value is not wait_timeout and not wait_failed, then the WAIT_OBJECT_0 should be subtracted from the return value. The resulting number is the index in the array of handles passed to WaitForMultipleObjects as the second argument. The index indicates which object has changed to the notified state. Here are some sample code to illustrate this situation:

HANDLE h[3];h[0] =hprocess1;h[1] =hprocess2;h[2] =Hprocess3;dword DW= WaitForMultipleObjects (3, H, FALSE, the);Switch(DW) { Casewait_failed://Bad call to function (invalid handle?)         Break;  Casewait_timeout://None of the objects became signaled within milliseconds         Break;  CaseWait_object_0 +0:        //The process identified by h[0] (HPROCESS1) terminated         Break;  CaseWait_object_0 +1:        //The process identified by h[0] (HPROCESS2) terminated         Break;  CaseWait_object_0 +2:        //The process identified by h[0] (HPROCESS3) terminated         Break;}

If you pass false,waitformultipleobjects for the fWaitAll parameter, the handle array is scanned starting at index 0, and the first object notified terminates the wait state. This may produce some results that you do not want. For example, by passing 3 process handles to the function, your thread waits for 3 child processes to terminate. If a process with index 0 in the array is terminated, WaitForMultipleObjects will return. At this point the thread can do whatever it needs, and then loop back and forth, waiting for the other process to terminate. If the thread passes the same 3 handles, the function returns WAIT_OBJECT_0 again immediately. The code does not run correctly unless you delete a handle that has been notified.

2 side effects of successful waiting

For some kernel objects, the successful invocation of WaitForSingleObject and WaitForMultipleObjects actually alters the state of the object. A successful call means that the function discovers that the object has been notified and returns a value relative to WA I T O B J E C T 0. If the function returns WA i t t i M e O U t or wa i t FA i L E D, then the call is unsuccessful. If the function call does not succeed, the state of the object cannot be changed.
When the state of an object changes, I call it the side effect of a successful wait. For example, one thread is waiting for the event object to be purged automatically (described later in this chapter). When the event object becomes a notified state, the function discovers the condition and returns the WA I T O B J E C T 0 to the calling thread. But just before the function returns, the event will be set to the non-notification state, which is the side effect of a successful wait.
This side effect will be used to automatically clear the kernel object because it is one of the rules defined by the M i c R o s o f t for this type of object. Other objects have different side effects, and some objects have no side effects at all. Process and thread kernel objects have no side effects at all, i.e. waiting on one of these objects never alters the state of the object. Since this chapter introduces a variety of kernel objects, we will explain in detail the side effects of their successful wait.
What makes the WaitForMultipleObjects function so useful, because it can perform all its operations in an atomic manner. When a thread calls the WaitForMultipleObjects function, the function can test the notification state of all objects and be able to execute all the necessary side effects as an action.
Let's look at an example. Two threads call WaitForMultipleObjects in exactly the same way:

Windows API learns to synchronize---threads with kernel objects

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.