VC in the recent multi-threaded comparison of interest, check the information, feel this write more practical. The content of the blog is partially corrected to practical VS2013.
http://blog.csdn.net/chen825919148/article/details/7904169
First, the question of the proposed
Write a time-consuming single-threaded program:
Create a new dialog-based application Singlethread, in the main dialog box Idd_singlethread_dialog Add a button, ID idc_sleep_six_second, titled "Delay 6 Seconds", add a button response function, The code is as follows:
void Csinglethreaddlg::onsleepsixsecond ()
{
Sleep (6000); 6 seconds delay
}
Compile and run the application, click the "Delay 6 seconds" button, you will find that during this 6 seconds the program as "dead", not in response to other messages, unable to move the window, cannot be canceled. To better handle this time-consuming operation, we need to learn-multithreaded programming.
Ii. Overview of Multithreading
Both processes and threads are concepts of the operating system. A process is an instance of an application that consists of a private virtual address space, code, data, and various other system resources, and the resources created during the process are destroyed as the process terminates, and the system resources used are freed or closed when the process terminates.
A thread is an execution unit within a process. After the system has created a process, the main execution thread that executes the process is actually started, and the main execution thread provides the program's startup point to the Windows system in the form of a function address, such as the main or WinMain function. The primary execution thread terminates, and the process terminates with it.
Each process has at least one master execution thread, which is created automatically by the system without the user being actively created. The user creates additional threads in the application as needed, and multiple threads run concurrently in the same process. All the threads in a process use these virtual address space, global variables and system resources together in the virtual address space of the process, so communication between threads is very convenient, and multithreading technology is widely used.
Multithreading enables parallel processing, avoiding a task that takes up CPU time for a long time. The point is that most of the computers are single-processor (CPU), in order to run all these threads, the operating system for each independent thread to schedule some CPU time, the operating system to provide the thread of time slices in a rotational manner, which gives a false impression, as if these threads are running concurrently. This shows that if two very active threads in order to rob the control of the CPU, the thread switching will consume a lot of CPU resources, but will reduce the performance of the system. This should be noted in multithreaded programming.
The WIN32 SDK function supports multi-threaded programming and provides various synchronization, mutex, and critical areas in operating system principles. In Visual C + + 6.0, the use of MFC class Library also implements multi-threaded programming, making multithreading more convenient.
Iii. Win32 API support for multithreaded programming
WIN32 provides a series of API functions to complete thread creation, suspend, resume, terminate, and communicate. Some of these important functions are selected below.
1, HANDLE CreateThread (lpsecurity_attributes lpthreadattributes,
DWORD DWSTACKSIZE,
lpthread_start_routine lpstartaddress,
lpvoid LPPARAMETER,
DWORD dwcreationflags,
Lpdword Lpthreadid);
The function creates a new thread in the process space of its calling process and returns a handle to the built thread, with the parameters described below:
Lpthreadattributes: A pointer to a security_attributes structure that determines the security attributes of a thread and is generally NULL;
Dwstacksize: Specifies the thread's stack depth, which is generally set to 0;
Lpstartaddress: Represents the address of the function that the code is in when the new thread starts executing, that is, the starting address of the thread. The general situation is (Lpthread_start_routine) Threadfunc,threadfunc is the name of the thread function;
Lpparameter: Specifies the 32-bit parameter that the thread performs simultaneous to the thread, which is the parameter of the thread function;
dwCreationFlags: To control the additional flags created by the thread, you can take two kinds of values. If the parameter is 0, the thread starts executing immediately after it is created, and if the parameter is create_suspended, the thread is suspended after the system generates the thread, and is not executed immediately until the function resumethread is called;
Lpthreadid: This parameter returns the ID of the created thread;
Returns a handle to the thread if creation succeeds, otherwise null is returned.
2, DWORD SuspendThread (HANDLE hthread);
The function is used to suspend the specified thread, and if the function executes successfully, the execution of the thread is terminated. 3, DWORD ResumeThread (HANDLE hthread);
This function is used to end a thread's pending state and execute the thread. 4, VOID ExitThread (DWORD dwexitcode);
This function is used for the execution of the thread termination itself, which is called in the execution function of the main threads. Where parameter dwexitcode is used to set the thread's exit code. 5, BOOL TerminateThread (HANDLE hthread,dword dwexitcode);
In general, the thread function returns normally after the thread has finished running, but the application can invoke TerminateThread to forcibly terminate the execution of a particular thread. Each parameter has the following meanings:
Hthread: The handle of the thread that will be terminated;
Dwexitcode: The exit code used to specify the thread.
Terminating execution of a thread with TerminateThread () is unsafe and may cause system instability, although the function terminates the execution of the thread immediately, but does not release the resources that the thread occupies. Therefore, it is generally not recommended to use this function.
6, BOOL postthreadmessage (DWORD idthread,
UINT MSG,
WPARAM WPARAM,
LPARAM LPARAM);
The function places a message into the message queue of the specified thread and returns without waiting for the message to be processed by the thread.
Idthread: The ID of the thread that will receive the message;
Msg: Specifies the message to be sent;
WParam: Word parameters related to the message;
LParam: Long parameters related to the message;
When this function is called, the function fails to execute if the thread that is about to receive the message does not create a message loop.
Iv. WIN32 API multithreaded programming routines
Routine 1 MultiThread1
Create a dialog based project MultiThread1, add two buttons and an edit box in the dialog idd_multithread1_dialog, the IDs of the two buttons are idc_start,idc_stop respectively, the title is "Start", "Stop", The Idc_stop property is checked disabled; The ID of the edit box is Idc_time, and the property is selected read-only;
Add the thread function declaration in the MultiThread1Dlg.h file: void ThreadFunc ();
Note that the declaration of the thread function should be outside the class Cmultithread1dlg. Add protected type variables inside class Cmultithread1dlg: HANDLE hthread;
DWORD ThreadID;
Represents the handle and ID of the thread, respectively.
Add the global variable M_brun:volatile BOOL m_brun in the MultiThread1Dlg.cpp file;
M_brun represents whether the thread is running.
Notice that the global variable, M_brun, uses the volatile modifier, which tells the compiler that it doesn't need to be optimized for that variable, that it doesn't have to be placed in a register, and that the value can be changed externally. For global variables referenced by multithreading, volatile is a very important modifier.
To write a thread function:
void ThreadFunc () {CTime time; CString Strtime;m_brun=TRUE; while (m_brun) { time =ctime::getcurrenttime (); Strtime=time. Format ("%h:%m:%s"); :: Setdlgitemtext (AfxGetMainWnd (),m_ Hwnd,idc_time,strtime); Sleep (+);}}
The thread function has no parameters and does not return a function value. As long as M_brun is true, the thread runs all the time. It is important to note that, after VC6.0, AfxGetMainWnd ()->m_hwnd Gets the handle of the main window changed, using AfxGetApp ()->m_pmainwnd->m_hwnd instead. Otherwise the compilation has no errors, but there is a memory conflict.
Double-click the Idc_start button to complete the message function for the button:
void Cmultithread1dlg::onstart () {// Todo:add your control notification handler codehere Hthread =CreateThread (null ,0, (lpthread_start_routine) ThreadFunc, null, 0 , &ThreadID); GetDlgItem (Idc_start),EnableWindow (FALSE); GetDlgItem (idc_stop),EnableWindow (TRUE);}
Double-click the Idc_stop button to complete the message function for the button:
void Cmultithread1dlg::onstop () {// Todo:add your control notification handler codehere m_brun=< C4>false; GetDlgItem (Idc_start),EnableWindow (TRUE); GetDlgItem (idc_stop),EnableWindow (FALSE);}
Compile and run the routine and experience multithreading written using the Win32 API.
Routine 2 MultiThread2
The thread demonstrates how to route an integer parameter into a thread, and how to wait for a thread to finish processing.
Create a dialog-based project MultiThread2, add an edit box and a button in the dialog idd_multithread2_dialog, the ID is Idc_count,idc_start, the button control is titled "Start";
Add a thread function declaration in the MultiThread2Dlg.h file: void threadfunc (int integer);
Note that the declaration of the thread function should be outside the class Cmultithread2dlg.
Add protected type variables inside class Cmultithread2dlg: HANDLE hthread;
DWORD ThreadID;
Represents the handle and ID of the thread, respectively.
Open ClassWizard and add the int variable m_ncount for the edit box Idc_count. In the MultiThread2Dlg.cpp file, add:
void ThreadFunc (int integer) {int i; for (i=0; i<integer;i++) { Beep (+); Sleep (+);}}
Here beep () for buzzer sound. The first parameter is the frequency and the second one is long. The original 200Hz frequency is low, inaudible, can be converted to 2000, more loud.
Double-click the Idc_start button to complete the message function for the button:
void Cmultithread2dlg::onstart () {updatedata (TRUE); int integer=m_ncount;hthread=CreateThread (NULL, 0, (lpthread_ Start_routine) ThreadFunc, (VOID*) Integer, 0, & ThreadID); GetDlgItem (Idc_start),EnableWindow (FALSE); WaitForSingleObject (Hthread,infinite); GetDlgItem (Idc_start),EnableWindow (TRUE);}
By the way WaitForSingleObject function, its function prototype is: DWORD WaitForSingleObject (HANDLE hhandle,dword dwmilliseconds);
Hhandle is a handle to the object to be monitored (typically a synchronous object or a thread);
Dwmilliseconds The timeout value set for the Hhandle object, in milliseconds;
When the function is called in a thread, the threads are temporarily suspended and the system monitors the state of the object pointed to by Hhandle. If a thread waits for a signaled state within a suspended dwmilliseconds millisecond, the function returns immediately if the time-out has reached dwmilliseconds milliseconds, but the object pointed to by Hhandle has not become signaled, and the function returns. The parameter dwmilliseconds has two values with special meaning: 0 and infinite. If 0, the function returns immediately, and if infinite, the thread is suspended until the object pointed to by Hhandle becomes signaled.
The function of this routine call is to press the Idc_start button, wait until the thread returns, and then restore the Idc_start button to its normal state. Compile and run the routine and experience it carefully.
Routine 3 MultiThread3
It is also possible to transfer a struct to a thread function, which can be accomplished by passing a pointer parameter to the struct. First define a structure body:
struct {int Firstargu,long Secondargu,...} MyType,*pmytype;
CreateThread (Null,0,threadfunc,pmytype,...) when creating threads;
Within the ThreadFunc function, you can use cast:
int intvalue= ((pmytype) lpvoid)->firstargu;
Long longvalue= ((pmytype) lpvoid)->seconddargu;
......
Routine 3 MultiThread3 will demonstrate how to route a pointer parameter to a struct body.
Create a dialog-based project MultiThread3, add an edit box to the dialog Idd_multithread3_dialog Idc_millisecond, a button Idc_start, titled "Start", a progress bar idc_ PROGRESS1;
Open ClassWizard, add int variable m_nmillisecond for edit box idc_millisecond, add CProgressCtrl type variable m_ctrlprogress for progress bar Idc_progress1;
Add a structure definition to the MultiThread3Dlg.h file:
struct Threadinfo{uint Nmillisecond; CProgressCtrl* pctrlprogress;};
Declaration of the thread function: UINT threadfunc (LPVOID lpparam);
Note that the two should be outside the class Cmultithread3dlg.
Add protected type variables inside class Cmultithread3dlg: HANDLE hthread;
DWORD ThreadID;
Represents the handle and ID of the thread, respectively.
In the MultiThread3Dlg.cpp file, do the following:
Define public variables Threadinfo Info;
Double-click the button idc_start to add the corresponding message handler function:
voidCmultithread3dlg::onstart () {//Todo:add your control notification handler code hereUpdateData (TRUE); Info.nmillisecond=m_nmillisecond;info.pctrlprogress=&M_ctrlprogress;hthread=CreateThread (NULL,0, (lpthread_start_routine) ThreadFunc,&Info,0, &ThreadID);/*GetDlgItem (Idc_start)->enablewindow (FALSE); WaitForSingleObject (Hthread,infinite); GetDlgItem (Idc_start)->enablewindow (TRUE);*/}
Add a statement in the function bool Cmultithread3dlg::oninitdialog ():
{... // Todo:add Extra Initializationhere M_ctrlprogress.setrange (0); m_nmillisecond =ten; UpdateData (FALSE); return TRUE; // return TRUE unless you set the focus to a control}
To add a thread handler function:
uint threadfunc (lpvoid lpparam) {threadinfo * pinfo= (Threadinfo* for (int i=0 ;i< 100 ; I++) { int ntemp=pinfo->nmillisecond; PInfo ->pctrlprogress->setpos (i); Sleep (ntemp);} return 0 ;}
By the way, if you add the/* */statement in the Void Cmultithread3dlg::onstart () function, you will see that the progress bar does not refresh and the main thread stops responding. What's the reason? This is because the WaitForSingleObject function waits for the child thread (THREADFUNC) to end, causing the thread to deadlock. Because the WaitForSingleObject function suspends the main thread (any message is not processed), and the child thread ThreadFunc is setting the progress bar, the notification event is not detected until the main thread has finished processing the flushing message. So two threads are waiting for each other, the deadlock has occurred, and should be avoided when programming.
Routine 4 MultiThread4
This routine tests the maximum number of threads that can be created under Windows.
Create a dialog-based project MULTITHREAD4, add a button idc_test and an edit box in the dialog Idd_multithread4_dialog Idc_count, the button title is "Test", the edit Box property is selected Read-only;
In the MultiThread4Dlg.cpp file, do the following:
Add public variable volatile BOOL m_brunflag=true;
The variable indicates whether the thread can continue to be created.
To add a thread function:
DWORD WINAPI threadfunc (lpvoid threadnum) {while(m_brunflag) { Sleep ( );} return 0 ;}
As long as the M_brunflag variable is true, the thread runs all the time.
Double-click the button idc_test to add its response message function:
voidcmultithread4dlg::ontest () {DWORD ThreadID; GetDlgItem (idc_test)-EnableWindow (FALSE); LongNcount=0; while(m_brunflag) {if(CreateThread (NULL,0, Threadfunc,null,0, &threadid) = =NULL) {M_brunflag=FALSE; Break; }Else{ncount++; }}//threads are created continuously until they can no longer be createdM_ncount=ncount; UpdateData (FALSE); Sleep ( the); //5 seconds delay, waiting for all created threads to endGetDlgItem (Idc_test)EnableWindow (TRUE);
M_brunflag=true;
}
MFC Multithreaded Creation Tutorial sample