Abstract: all applications in windows are actually running in a thread mode. In the design of multi-threaded applications, it is sometimes necessary to maintain a certain synchronization relationship between threads, so that users can effectively control the independent running threads. This article briefly introduces the concept of a thread in windows and its creation method. After that, it proposes a method for controlling event synchronization between multiple threads using event objects. At last, we also introduced how to control synchronization events between different applications. This method makes it easy for different applications to control synchronization events.
I. Introduction
Windows is a multi-task and multi-thread operating system. Every application in Windows is a process ). A process can create multiple concurrent threads, and the process is scheduled by the system in the form of a primary thread. The so-called thread is a basic unit of System Scheduling. In a program, a thread appears in the form of a function, and its code is part of the process code, and share the public information such as the global variables and file opening table of the process with the process and other derived threads. The main thread is similar to the parent process in the Unix system, and the thread is similar to the child process. The main thread is also a thread, called the main thread, just to distinguish it from the thread it creates. Each thread runs independently from the main thread. To allow the thread to respond to user control, the thread must be controlled, for example, you can pause, terminate the running of a thread, or change the Running Conditions of the thread. In addition, there should be a certain synchronization control relationship between user control and thread running to ensure the user's effective control over the thread. The thread can make different responses to user control according to different conditions. To achieve the above purpose, you must use the synchronization object provided by the system, such as the event object. Win32 APIs must be used to write multi-threaded applications.
Ii. How to Create a thread
Call the createthread function in Win32 API to create a thread. Hthread = createthread (null, 0, & teventwindow: threadfunc, this, 0, & hthreadid); the first parameter sets the thread security attribute, because it is only used for Windows NT, therefore, this parameter is not set. The second parameter is 0, indicating that the thread uses the default stack size. The third parameter specifies the thread function. The thread starts to run at the entry of the function. When the function is returned, the thread stops running. The fourth parameter is a thread function parameter, which can be a pointer to any data type. The fifth parameter sets the thread generation flag. Hthreadid stores the ID of the thread. The thread function is defined as follows. The preceding this parameter is the handle pointer to the window to which the thread belongs. It is transmitted through the thrdwin parameter and then called by the pointer corresponding loopfunc function, the specific transactions of the thread are all executed in this function.
DWORD _ stdcall teventwindow: threadfunc (void * thrdwin ){
Return static_cast (teventwindow *, thrdwin)-> loopfunc ();
}
Iii. Thread Synchronization Event Control Method
Windows 95 provides two basic types of system objects. One is mutually exclusive objects used to coordinate access to data, such as mutex objects, and the other is event synchronization objects, used to send commands or trigger events and arrange the sequence of event execution, such as event objects. System Objects are valid within the system. They all have their own security attributes, access permissions, and one of the following States: signaled and nonsignaled. If you call the setevent function for an event object, you can set its status to signaled, and call the resetevent function to set its status to nonsignaled. The threads in the demo program continuously display the running results in a large loop. The thread stops running only when the user wants to close the window. However, the thread must be terminated before the window is closed. Otherwise, the running result of the thread will be displayed elsewhere on the screen, therefore, it is necessary to establish a synchronization relationship between the end of the thread and the close of the window. Therefore, two event objects are created in the constructor of the teventwindow class for event synchronization.
Hcloseevent = createevent (0, false, false, 0); hnocloseevent = createevent (0, false, false, 0 );
The second parameter is false, indicating that an automatic event object is created. The third parameter is false, indicating that the initial state of the object is nonsignaled. The fourth parameter is 0, indicating that the object has no name.
The hwatchevent and hntyevent objects are also created in the constructor of the teventwindow class. The initial state is nonsignaled. When the user wants to close the window, the program first calls the canclose function and sets the state of the hcloseevent object to signaled in this function. This method is used to notify the thread and require the thread to terminate the operation. Then the main thread calls the waitformultipleobjects function (this function is hereinafter referred to as the wait function). The wait function first checks whether the status of any of the hthread and hnocloseevent objects is signaled, if none of the above conditions are met, the main thread will be blocked until the preceding conditions are met. If an object is in signaled state, the wait function will return and no longer block the main thread. If the object is an automatic event object, the wait function sets the object state to nonsignaled before returning the object. In the wait function, the parameter "false" indicates that the status of both objects is not required to be signaled at the same time. The parameter "-1" indicates that the two objects are waiting for an indefinite period until the conditions are met. Parameter 2 indicates that there are two objects in the signalsc array.
In Windows 95, a thread is also regarded as a system object and has two states. When a thread is running, its status is nonsignaled. If the thread stops running, its status is set to signaled automatically by the system (the thread status can be obtained through the thread handle hthread). At this time, the wait function returns 0, indicates that the first object meets the conditions, and canclose returns true, indicating that the window can be closed. If the thread cannot meet the conditions for terminating the operation, set the hnocloseevent object to signaled. At this time, the wait function returns 1, the second object meets the conditions. Therefore, canclose returns false, indicating that the window cannot be closed yet. Bool teventwindow: canclose (){
Handle signalsc [2] = {hthread, hnocloseevent };
Setevent (hcloseevent );
If (waitformultipleobjects (2, signalsc, false,-1) = 0) return true;
Else return false;
}
Another example of user control is that the user suspends the main thread until the thread meets certain conditions. For example, after you select the "watch" menu, the main thread calls the following function to start monitoring the computing data of the thread. First, set the state of the hwatchevent object to signaled to notify the thread. The main thread has entered the waiting state and starts to monitor the data. Then the main thread calls the wait function to wait for the thread to respond. The thread sets the state of the hntyevent object to signaled after a condition is met, so that the main thread ends the waiting state and continues to run.
Void teventwindow: cmwatch (){
Setevent (hwatchevent );
Waitforsingleobject (hntyevent,-1 );
: MessageBox (getfocus (), "the thread has met the conditions, and the main thread continues to run! "," ", Mb_ OK );
}
The loopfunc called by a thread function is a large loop that constantly judges the state of the synchronization object and performs corresponding operations based on the state of the object. These objects are listed in the array signalsl. The arrangement order of each element in this array is very important. The first two objects correspond to two different user control events respectively, by judging the object status, you can know which user control is triggered. The status of the third object is determined only when the current two objects are not signaled. This ensures that the thread can detect all user control events, on the other hand, it ensures that the thread can continue running without a user control event. Therefore, the hnoblockevent state of the object created in the teventwindow constructor is always signaled.
Hnoblockevent = createevent (0, true, true, "myevent ");
The second parameter "true" indicates that a manually created event object will not be changed by the wait function unless the resetevent function is explicitly called. The third parameter is true, indicating that the initial state of the object is signaled. The fourth parameter defines the object name as "myevent ". The loopfunc function calls the wait function. If the hcloseevent status is signaled, the wait function returns 0. When the thread knows that the user wants to close the window, it determines whether the thread can terminate, the condition is icount> 100. If the loopfunc function meets the condition for termination is returned, the thread is actually terminated. If the condition is not met, the hnocloseevent object is set to signaled, let the main thread know that the thread cannot be terminated yet. Because hcloseevent is an automatic event object, when the wait function returns 0, the state of the hcloseevent object is set to nonsignaled, so that in the second loop, the wait function does not determine whether the State of the hcloseevent object is signaled. This prevents the thread from incorrectly determining whether the condition for termination is met. If the wait function detects that the hwatchevent status of the object is signaled, the wait function returns 1. The thread knows that the main thread has entered the waiting status and is monitoring the data, set the value of the variable bwatch to true. If neither of the preceding events occurs, the state of the first two objects is nonsignaled. Therefore, the wait function checks the state of the third object. Because the state of the third object hnoblockevent is always signaled, therefore, the thread continues to run without interruption, and the variable icount is continuously added. When the variable is greater than 200, if bwatch is set to true, the state of hntyevent is set
Signaled, so that the main thread stops waiting and continues to run.
DWORD teventwindow: loopfunc (){
Handle signalsl [3] = {hcloseevent, hwatchevent, hnoblockevent };
Static bool bwatch = false; int dwevent;
While (1 ){
Dwevent = waitformultipleobjects (3, signalsl, false,-1 );
Switch (dwevent ){
Case 0: If (icount> 100) return 0;
Else setevent (hnocloseevent );
Break;
Case 1: bwatch = true; break;
Case 2: ++ icount;
If (bwatch & icount> 200) setevent (hntyevent );
Break;
}
}
}
Iv. multi-thread synchronization event control method between processes
Because the event object is valid within the system, another process (that is, an application, itself is also a thread) can call the openevent function to obtain the object handle through the object name, however, the object must have been created and can be used in functions such as resetevent, setevent, and waitformultipleobjects. In this way, the thread of a process can control the running of the thread generated by another process. The following statement obtains the handle of the hnoblockevent object generated by the above process through the object name "myevent", and then sets the object state to nonsignaled using this handle. In the above loopfunc function, the above thread is paused because the object state has changed.
Handle hevent = openevent (event_all_access, true, "myevent ");
Resetevent (hevent );
The first parameter of the openevent function indicates the access permission of the call thread of the function to the event object. For example, if the thread has all the access permissions of the object, select the event_all_access parameter, in this way, the thread can use the resetevent function to change the object state. The true parameter indicates that the child process derived from this process can inherit the handle. The last parameter indicates the name of the event object. Use the following statement to set the status of the hnoblockevent object to signaled, so that the thread can continue to run, such as setevent (hevent ).
When a process no longer uses this handle, it can use the closehandle function to close the object handle. However, for the same event object, it may be used in other threads, therefore, the object will be released by the system only after all of its referenced handles are closed, all event objects mentioned in this Article play a controlling role between the main thread and between different processes 1:
① ── ─ ── ①: Close the window ── ─ ┤ Hcloseevent ── ┐ ②: Response to the above event │ └ ── ─ ┘ │ | │ ── ─ ┐ ↓ | Pause/resume thread running │ Hthread or │ ② ┌ ── ┐ ── ─ ┐ ┌ ── ┐ ─ ── ┐ ┌ ┤ Hnocloseevent when there are two threads waiting for hnoblockevent when there are two processes 2 │ │ The main thread is always starting and running ── ─ │/Process 1 → ┐ ── ─ ┐ │ | between different processes └ ── ┬ ── ⑴ (1) └ ┤ hwatchevent ── ┘ │ | Address limit ↑ ── ─ ┘ │ │ ┌ ── ─ ┐ │ (1): Monitoring Data ── ┤ Hntyevent ├ ← ── ⑵ (2): The thread meets the monitoring conditions. └ ── ─ ┘ (2) |
Figure 1 Role of event objects in synchronization event control among multiple threads
V. Conclusion
Multithreading programming technology has broad application prospects in multimedia, network communication, mathematical computing and real-time control. Of course, in actual programming, the situation is often very complicated, at this time, we should note how to accurately divide tasks into concurrent threads and arrange the elements in the signalsl array mentioned in this article. This article is also helpful for designing Multithreaded Applications in Windows NT or some UNIX systems that support multithreading.