Real the scheduling and processing of multi-threaded by VC 5.0
Harbin Congress, a series of Zhang Wanchun
More tasks, multi-process and multi-threaded
---- Windows95 and WindowsNT Operation System Support Multi-tasking Scheme and Processing, based on the multi-task space provided by this feature, the programmer can perform the operation of each piece in the full control application program, and write high-efficiency application procedures.
---- What multi-tasks often include this two major categories: multi-process and multi-thread. The process refers to an application program that is running in the system; the thread is a basic unit of system-assigned processing system, or a unit that is independent within the process. For the operation system, its degree unit is a thread. One process is at least one thread, and the thread is often called the main thread. A process creates one or more additional threads from the execution of the main thread, which is the multi-threaded multi-line.
---- Development Multi-threaded Application Program can be used to use the 32-bit Windows environmental Win32 API interface function, can also be developed with the MFC class library available in VC . Multi-threaded programming is in these two equations, and users can choose the tools to select. This paper focuses on the MFC class library with VC 5.0, real-multi-threaded score and processing method, and the same step multi-task feature introduced by the thread multi-task, the last multi-task is explained in detail.
Two-based MFC multi-threaded programming
---- 1 MFC support for multi-threaded
---- The MFC library provides multi-threaded programming, which is more addressed to the user. One thing for non-important is that in the case of multi-window thread, the MFC directly provides the design of the user interface thread.
---- MFC distinguish between two types of threads: auxiliary thread and user interface. The auxiliary thread does not have a message mechanism, which is commonly used to implement the background counting and maintenance tasks. The MFC is used to provide a job machine system for use, use the income of the user, responding to the incoming events and messages. But for the Win32's API, these two threads do not have a zone, it only needs the starting address of the thread to start the thread. A typical application of the user interface thread is class CWINAPP. The big house is more familiar with CWINAPP. It is a custom class of the CWINTHREAD class. The main thread of the application program is supplied by it, and it is responsible for managing the household generated events and messages. Class CWINTHREAD is a base class for user interface threads. CWINTHREAD 's object is used to maintain a local data of a specific thread. Because of the partial data of the processing thread relies on Cwinthread, the thread with the MFC with the MFC must be created by the MFC. For example, the thread created by the Run-Time function _BeginThreadex cannot use any MFC API. - 2 2 Auxiliary threads and the creation of the user interface thread
---- To create a thread, you need to call the function AFXBEGINTHREAD. This function has two editions through the parameter overload, and part is divided into auxiliary thread and user interface thread. None the auxiliary thread or the user interface thread, you need to specify an additional parameter to repair the priority, the stack is small, the creation of the standards and the full characteristics. Functions AFXBEGINTHREAD returns a pointer to the Cwinthread class object.
---- Create a handling thread to simple. Just need two steps: Real Control Functions and Start Threads. It does not have to send a class from the CWINTHREAD. Simply, as follows:
--- 1. Real the control function. Control Function Defining the thread. When entering the function, the thread is enabled; when it is retracted, the thread ends. The control function sounds as follows:
Uint MyControllingFunction (LPVOID PPARAM);
---- This parameter is a single-precision 32-bit value. The value received by the parameter will pass the thread pair to create a function of the construct. The control function will explain this value in some way. It can be a numerical value, or means a pointer including a plurality of parameters, or even ignore it. If this parameter refers to the structure, it is not only possible to pass the data from the call function to the thread, or the callback function can be transmitted from the thread. If you use this symbol back to data, the thread should notify the call function when the results are ready. When the function is completed, a UINT type value value should be returned, indicating the cause of the end of the end. Tongmong, return to 0 tables to work, and its value is different from the wrong mistake. ---- 2. Exposing the thread. Create a CWINTHREAD class to the address of the CWINTHREAD class, start and return the address of the thread. The thread enters the operational state.
---- 3. For example, it is said. Under the simple code, it is clear how to define a control function and use it in other parts of the program.
Uint MythreadProc (LPVOID PPARAM)
{
CMYOBJECT * POBJECT = (CMYObject *) PPARAM;
IF (POBject == Null ||
POBJECT-> iskindof (runtime_class (cMyObject))))))
Return -1; // illegal parameters
... // Specific implementation
Return 0; // thread successfully ended
}
/ / Call the function of the thread in the program
......
PNEWOBJECT = New CMYOBJECT;
AfxBeginthread (MythreadProc, PnewObject);
......
There are two ways to create user interface threads.
---- The first method, first send a class from the CWintread class (Note) to sound and implement the class with macro declare_dyncReate and import_dyncreate; then call the function AFXBEGINTHREAD Creating the CWINTHREAD Association's object to the initialization starting thread. In addition to the call function AfXbeginthread, you can use the second method, that is, a pair of confined function creation category CWINTHREAD, then reparters by programmer: CreateThread to start the thread. Tongmong Class CWINTHREAD The auto-moving will end when the context of the context of the thread, such as the fruit program, I hope to control the M_Bautodelete to False. This is still saved after the end of the thread, but it is only necessary to manually delete the CWINTHREAD object in this situation.
---- After the end of the normal thread function, the thread will end the line. Class CWINTHREAD will work for us to end the end of the thread. If the process of executing the process of the thread is looking forward to the end of the thread, you need to call AFXendThread (Nexitcode) in the thread. Its parameter is the thread end harness code. This will end the thread running and release the resources occupied by the thread. If the thread is changed from another thread, it must set the communication method in two threads. If the thread is left from the thread, it can also be used to use Win32 functions (CWINTHREAD category does not provide this member function): BOOL TerminateThread (Handle Hthread, DWORD DWEXITCODE). However, in the actual order setting, the use of the function should be careful. Because of the order of this command, the thread will be terminated, and the resources occupied by the thread are not released. This may lead the system unstable. ---- If the thread that has been terminated is the last thread in the process, the process of the thread ends will end.
---- 3 Excellent priority issues for advances and threads
---- In the Windows 95 and WindowsNT operations, the task is priority, a total of 32, from 0 to 31, and the system is operated by the unique pre-level scheduled thread.
---- 1) No. 0-15 is Pu Tong Premium Level, and the priority of the thread can be dynamically changed. The high-level leading thread is prior to operation, only the high-level leading thread is not running, the low-priority thread is scheduled. The same thread is running in the time of time. 2) 16-30 is a real-time priority, the biggest difference between real-time priority and normal priority is that the operation of the same priority process does not follow the time slice, but the thread that runs first, then controls the CPU, if it does not actively give up The thread that controls, the same or low priority is unable to run.
---- You first a class first first belongs to a class, then it is the opposite place in this class. The thread prior grade calculation can be shown in the following formula:
---- Thread priority level = process class basic priority thread phase of superior level
---- Basic Professional Premium Class:
IDLE_PROCESS_CLASS
NORMAL_PROCESS_CLASS
HIGH_PROCESS_CLASS
REAL_TIME_PROCESS_CLASS
Thread relative priority:
Thread_Priority_Idle
(Minimum priority, only in system free)
Thread_Priority_lowest
Thread_Priority_BELOW_NORMAL
Thread_Priority_NORMAL (default)
Thread_priority_above_normalthread_priority_highest
Thread_Priority_Critical
(Very high priority)
---- 4 Treading Procedure
---- The most important question of the programming of multi-threaded should be the source of resources between the threads. Due to multiple threads, there is often an incorrect result in the occurrence of the hair. For example, a thread is being updated with a structured content, another thread is trying to read the same structure. As a result, we will not know how to know what is read, is it: old data, new data, or mixed?
---- MFC provides a set of steps and synchronous interviews to solve this problem, including:
---- Synchronous object: CsyncObject, CSemaphore, Cmutex, CcriticalSECTION and CEVENT; symptoms: CMULTILOCK and CSILOCK.
---- Synchronous class is used to ensure the integration of resources when accessing resources. The CSyncObject is the base class of its four steps, not directly used. Signal synchronization class CSEMAPHORE is often used to access a resource in one application (for example, the application allows the same document to have multiple views); event synchronization class CEVENT is usually used to access resources in the application Previous application must wait (for example, the data must be obtained from the communication port before the data is written to a file; and for the mutually exclusive synchronous class CMUTEX and the critical area synchronous class ccriticalsection can ensure that one resource can only have one Thread access, the difference is that the former allows multiple applications to use this resource (for example, the resource in a DLL) and the latter does not allow access to the same resource to be more than the process of the process, and use critical regions The way is more efficient.
---- Song's interview class is used to obtain access to these control resources. CMULTILOCK and CSILOCK are only in order to control access to multiple or single resource objects.
---- 5 Similarity
---- A simple way to solve the problem is to integrate the same step into the shared class, and us often call this sharing class as a neutral class. The next example of the next example is clearly used. For example, an application program for use to maintain a set of accounts. This application allows 3 accounts to be detected in different windows, but only one account can be updated at a time. When an account is updated, you need to pass the updated data through the network to a data document. ---- This example will be used in three steps. Since the 3 accounts are allowed to detect, use CSEMaphore to limit the access to 3 window objects. When updating an account, you should use CcriticalSection to guarantee that there is only one account to update once. After updating the success, send a CEVENT signal, the signal releases a thread that is waiting to receive the signal. The thread passes the new data to the data document.
---- To set up a necklace, the first first, according to the body situation, add the same step class as a data member. In the case, you can add a CSEMAPHORE class to the window category, and a CCRITICALSECTION class data is added to the connected list class, and a CEVENT data is added to the data storage class.
---- After the function of using the shared resource is used to join a lock pair of synchronous access to the same step. That is, a CSINGLOCK or CMULTILOCK should be created in the member function of the access control resource and call the Lock function of the object. When the end of the interview, the Unlock function is called, and the resources are released.
---- Use this way to set up the neutrality of the thread. In the same time of ensuring the passage of the line, save the madness of the synchronization of the same step, which is also the thinking of OOP. But it is to use the line of the all-class method compared to the thread to be complex, especially in the program. Moreover, the wires and all-round processes will lose a partial efficiency, and the exchange between multiple threads in a single CPU computer will occupy a sub-resource.
Three-program example
---- Next, a simple-based MFC case in VC 5.0 is clearly realized, and the method of preaching multi-threaded task and processing is explained under detail.
---- Defining two user interface threads in this case, a cdisplaythread and a counting thread. These two threads operate a string variable m_strnumber, which is displayed in the thread to display the string in a list box, while the counting thread plus the integer in the string 1. In the case, the priority of the process, the counting thread, and the thread can be adjusted. The same step mechanism in the process uses CMUTEX and CSIGLOCK to ensure that the two threads cannot access the string. The Synchronous Equipment Execution and No Of the Exploitation Ringing Procedure. In this case, it will be allowed to suspend the two threads to check the results of the operation. The row of the counting thread is also allowed in the example. The question in this example is also a problem in multi-threaded programming in the multi-threaded program. ---- There are three combinations for adjusting priority when executed in this program, three check boxes for selecting synchronous mechanisms, displaying counting threads, and suspending threads, and a result of displaying List box.
---- In this program, two threaded CCOUNTHREADs and CDISPLAYTHREADs are used, and the two thread classes act together in the string of string objects M_Strnumber in cmutexesdlg. The method of this program on the same step CMutex is to be implemented in accordance with the merged method described in this article. The lock pair of CSIGLOCK in the same step is defined in the realization of the specifications of each thread.
---- The institution of this example is introduced under the following:
Use AppWizard to generate a programming framework named MUTEXES-based dialog box. Use the dialog box editor to fill in the dialog box: three sets frames, three checkboxes, and a list box. Three sets of frames are allowed to change the progressive level and two thread prizes, and their ID is set to: IDC_PriorityClass, IDC_DspythrdPriority and IDC_CNTRTHRDPRIORIRIRITY. Three check boxes are handled on the same steps, display the count threads, and the ID class is set to IDC_Synchronize, IDC_ShowCNTRTHRD, and IDC_PAUSE. The list box is used to display the common operation of the two threads in the thread display program M_StrNumber, and its ID is set to IDC_DATABOX. Create a class CEXAMPLETHREAD for Class CWINTHREAD. This class will be used as two thread classes used in this program: CCOUNTHREAD and CDISPLAYTHREAD's parent classes. The purpose of this is only for shared variables and functions for sharing two thread classes.
---- Fill in the header of Cexamplethread fill in the measuring parameters:
Cmutexesdlg * m_powner; // Point to class cmutexesdlg pointer BOOL M_BDONE; / / to control thread execution
And functions:
Void Setowner (cmutexesdlg * Powner)
{m_powner = Powner;}; // Take a pointer to cmutexesdlg
Then initialize the member variables in the constructor:
m_bdone = false; // Initialization allows thread operation
m_powner = null; // Place the pointer empty
m_bautode = false; // Require manually to delete thread objects
Create two threads CCOUNTHREAD and CDISPLAYTHREAD. These two thread classes are CEXAMPLETHREAD sent class. Differentially reload the :: run () function in the two threads, and realize the tasks of each thread. In these two classes, the lock objects of the same step access class are added to the Slock, which will be determined by the complexing of the same step mechanism and whether the no control system is access to the shared resource. Don't forget to add the header #include "afxmt.h".
---- Counting thread :: Run () function's weight-on code is:
Int ccounterthread :: run ()
{
BOOL FSYNCCHECKED; / / Synchronization mechanism check detection
Unsigned int nNumber; // Store integers in strings
IF (m_powner == null)
Return -1;
// Connect the synchronization object with the lock object
CSILOCK SLOCK (& (M_Powner-> m_mutex);
While (! m_bdone) // Controlling thread runs, for termination of thread
{
// Take synchronization mechanism check status
FSYNCCHECKED = m_powner->
IsdlgButtonChecked; IDC_SYNCHRONIZE
/ / Determine if the synchronization mechanism is used
IF (fsyncchecked)
Slock.lock ();
// Read an integer
_stscanf ((lpctstr) m_powner-> m_strnumber,
_T ("% d"), & nnumber
NNUMBER ; // plus 1
m_powner-> m_strnumber.empty (); // Character serial space
While (nnumber! = 0) // update string
{
m_powner-> m_strnumber =
(Tchar) ('0' nnumber% 10);
nnumber / = 10;
}
// Adjust string order
m_powner-> m_strnumber.makereverse ();
/ / If the synchronization mechanism is selected, the resource is released
IF (fsyncchecked)
Slock.unlock ();
/ / Determine check display counting thread
IF (m_powner-> isdlgbuttonchecked (idc_showcnthrd))
M_Powner-> AddtolistBox (_T ("Counter: Add 1"));
} // End While
M_Powner-> PostMessage (WM_Close, 0, 0L);
Return 0;
}
Show thread :: run () function overload code is:
Int cdisplaythread :: run ()
{
Bool fsyncchecked;
Cstring strbuffer;
Assert (m_powner! = Null); if (m_powner == null)
Return -1;
CSILOCK SLOCK (& (M_Powner-> m_mutex);
While (! m_bdone)
{
FSYNCCHECKED = m_powner->
IsdlgButtonChecked; IDC_SYNCHRONIZE
IF (fsyncchecked)
Slock.lock ();
// Build a string to display
Strbuffer = _t ("Display:");
Strbuffer = m_powner-> m_strnumber;
IF (fsyncchecked)
Slock.unlock ();
// Add a string into the list box
m_powner-> addtolistbox;
} // End While
M_Powner-> PostMessage (WM_Close, 0, 0L);
Return 0;
}
3 Add the following member variables in the header file of cmutexesdlg:
CString M_StrNumber; // The resource object to be operated by the thread
CMUTEX M_MUTEX; // Multi-mutual exclusion
CCOUNTERTHREAD * m_pcounterthread; // Pointer to the counting thread
Cdisplaythread * m_pdisplaythread; // Pointer to display threads
First, add the following code to the dialog box in the initialization function of the dialog:
Bool cmutexesdlg :: oninitdialog ()
{
......
// Initialization Process Priority Combination Box and default to Normal
CCOMBOBOX * PBOX;
Pbox = (ccombox *) getdlgitem (IDC_PRIORITYCLASS);
Assert (Pbox! = Null);
IF (pbox! = null) {
Pbox-> addstring (_t ("idle"));
Pbox-> addstring (_t ("normal");
Pbox-> addstring (_t ("high"));
Pbox-> addstring (_T ("realtime"));
Pbox-> setcursel (1);
}
// Initialize Display Thread Priority Combination Box and default to Normal
Pbox = (ccomboBox *) getdlgitem (idc_dspythrdpriority);
Assert (Pbox! = Null);
IF (pbox! = null) {
Pbox-> addstring (_t ("idle"));
Pbox-> addstring (_t ("limited"));
Pbox-> addstring (_T ("Below Normal");
Pbox-> addstring (_t ("normal");
Pbox-> AddString (_T ("Above Normal"));
Pbox-> addstring (_T ("highest"));
Pbox-> addstring (_t ("timecritical");
Pbox-> setcursel (3);
}
// Initialization Count Thread Priority Combination Box and default to Normal
Pbox = (ccomboBox *) getdlgitem (idc_cntrthrdpriority);
Assert (Pbox! = Null);
IF (Pbox! = null) {pbox-> addstring (_t ("idle"));
Pbox-> addstring (_t ("limited"));
Pbox-> addstring (_T ("Below Normal");
Pbox-> addstring (_t ("normal");
Pbox-> AddString (_T ("Above Normal"));
Pbox-> addstring (_T ("highest"));
Pbox-> addstring (_t ("timecritical");
Pbox-> setcursel (3);
}
// Initialization thread hang check box is a suspend state
CButton * PCheck = (cbutton *) getdlgitem (IDC_PAUSE);
PCHECK-> SetCheck (1);
// Initialization thread
m_pdisplaythread = (cdisplaythread *)
AFXBEGINTHREAD (runtime_class (cdisplaythread),
Thread_Priority_NORMAL,
0,
CREATE_SUSPENDED;
m_pdisplaythread-> setowner (this);
m_pcounterthread = (ccounterthread *)
AFXBEGINTHREAD (Runtime_Class (CCOUNTHREAD),
Thread_Priority_NORMAL,
0,
CREATE_SUSPENDED;
M_PCOUNTERTHREAD-> SetOwner (this);
......
}
Then fill a member function:
Void AddTOListBox (LPCTSTR SZBuffer); // Used to fill a list box display
The implementation code of this function is:
Void cmutexesdlg :: AddtolistBox (lpctstr szbuffer)
{
Clistbox * pbox = (clistbox *) getdlgitem (IDC_DATABOX);
Assert (Pbox! = Null);
IF (pbox! = null) {
INT x = pbox-> addstring (szbuffer);
Pbox-> setcurseel (x);
IF (Pbox-> getCount ()> 100)
Pbox-> deleteString (0);
}
}
---- After filling with ClassWizard to adjust the priority, two thread priorities and functions used to resiliate the thread.
---- Adjusting the Circular Professional Code is:
Void cmutexesdlg :: OnselChangePriorityClass ()
{
DWORD DW;
// Take the focus option
CCOMBOBOX * PBOX = (CCOMBOBOX *)
Getdlgitem (IDC_PRIORITYCLASS);
Int ncursl = pbox-> getcursel ();
Switch (ncursel)
{
Case 0:
DW = IDLE_PRIORITY_CLASS; BREAK;
Case 1:
DEFAULT:
DW = NORMAL_PRIORITY_CLAS; BREAK;
Case 2:
DW = high_priority_class; break;
Case 3:
DW = RealTime_Priority_Class; Break;
SetPriorityClass (GetCurrentProcess (), DW); // Adjustment Priority
}
---- Based on the code of the two threaded priority, the code is found to adjust a function of a function of the same ID. This function code is:
Void cmutexesdlg :: onprioritychange (uint NID)
{
Assert (NID == IDC_CNTRTRTHRDPRIORITY ||
NID == IDC_DSPYTHRDPRIORITY);
DWORD DW;
// Take the focus option for the ID ID
CCOMBOBOX * PBOX = (ccomboBox *) getdlgitem (NID);
Int ncursl = pbox-> getcursel ();
Switch (ncursel)
{
Case 0:
DW = (dWord) thread_priority_idle; break;
Case 1:
DW = (dWord) Thread_Priority_lowest; Break;
Case 2:
DW = (dword) thread_priority_below_normal;
Case 3:
DEFAULT:
DW = (dWord) thread_priority_normal;
Case 4:
DW = (dword) thread_priority_above_normal; Break;
Case 5:
DW = (dWord) thread_priority_highest;
Case 6:
DW = (dword) thread_priority_time_critical;
}
IF (NID == IDC_CNTRTHRDPRIORIRIRIRITY)
M_PCounTerthread-> SetthreadPriority (DW);
// Adjust the count thread priority
Else
m_pdisplaythread-> setthreadpriority (dw);
// Adjust the display thread priority
}
The adjustment of thread priority needs to be called according to different IDs:
Void cmutexesdlg :: OnselchangeDspythrdpriority ()
{OnPriorityChange (IDC_DSPYTHRDPRIORIRIRITY);
Void cmutexesdlg :: OnselchangecnTRTHRDPRIORITY ()
{Onprioritychange (idc_cntrthrdpriority);}
The implementation code that the check thread hang is as follows:
Void cmutexesdlg :: onpause ()
{
// Take the check box status
CButton * PCheck = (cbutton *) getdlgitem (IDC_PAUSE);
Bool bpaused = ((pcheck-> getState () & 0x003)! = 0);
IF (bpaused) {
M_PCOUNTERTHREAD-> SUSPENDTHREAD ();
m_pdisplaythread-> suspendthread ();
} // hang thread
Else {
m_pcounterthread-> resumeThread ();
m_pdisplaythread-> resumethread ();
} // Restore thread operation
}
---- The program is in :: onClose () to realize the end of the thread. In this case, the end of the thread is slightly more complicated. It is necessary to note that the work of the member variable m_bdone is required. When the thread is run, the appearance of the variable is detected, and the thread will finally lead the thread. The end of this thread is due to the backout of the function, rather than using the method of ending, which is beneficial to the system. The postMessage function is used in this program, and the function is sent back to the message, which can avoid blocking. Its real code is: void cmutexesdlg :: onClose ()
{
INT ncount = 0;
DWORD DWSTATUS;
// Take the check box status
CButton * PCheck = (cbutton *) getdlgitem (IDC_PAUSE);
Bool bpaused = ((pcheck-> getState () & 0x003)! = 0);
IF (bpaused == true) {
PCHECK-> setCheck (0); // check cancellation
m_pcounterthread-> resumeThread ();
// Restore thread operation
m_pdisplaythread-> resumethread ();
}
IF (m_pcounterthread! = null) {
Verify (:: getExitcodethread (m_pcounterthread->
m_hthread, & dwstatus)); // Take a number thread end code
IF (dWStatus == STILL_ACTIVE) {
NCOUNT ;
m_pcounterthread-> m_bdone = true;
} // If still is still a running state, terminate
Else {
Delete M_PCOUNTHREAD;
m_pcounterthread = null;
} // If you have already terminated, the thread object is deleted.
}
IF (m_pdisplaythread! = NULL) {
Verify (: getExitcodethread (m_pdisplaythread->
m_hthread, & dwstatus)); // Take the display thread end code
IF (dWStatus == STILL_ACTIVE) {
NCOUNT ;
m_pdisplaythread-> m_bdone = true;
} // If still is still a running state, terminate
Else {
Delete m_pdisplaythread;
m_pdisplaythread = NULL;
} // If you have already terminated, the thread object is deleted.
}
If (ncount == 0) // two threads are terminated, close the program
CDIALOG :: OnClose ();
ELSE / / otherwise send a WM_CLOSE message
Postmessage (WM_Close, 0, 0);
}
---- In the case of the case, many functions have been used in the real estate. Instead of this, there is nothing more than the functionality and usage of the function, and can be used to view the online help.