The process and thread of MFC are terminated abnormally.

Source: Internet
Author: User
Process Is an executable Program By private virtual address space, Code Data and other operating system resources (such as files, pipelines, and synchronization objects created by processes. An application can have one or more processes. A process can have one or more threads, one of which is the main thread.

ThreadIs the Basic entity for CPU time allocation during time-sharing scheduling in the operating system. A thread can execute any part of the code of the program, even if the code is concurrently executed by another thread; all threads of a process share their virtual address space, global variables, and operating system resources.

The thread concept is introduced because it is more efficient to schedule objects with threads rather than processes:

The code to be executed by the thread must be loaded when a new process is created, and the code to be executed by the thread has been mapped to the address space of the process. Therefore, the speed of creating and executing the thread is faster than that of the process.

All threads of a process share the address space and global variables of the process, so communication between threads is simplified.

Introduction to Win32 process Processing

Because MFC does not provide a class processing process, Win32 API functions are directly used.

Process Creation

Call the CreateProcess function to create a new process and run the specified program. The CreateProcess prototype is as follows:

Bool CreateProcess (
Lptstr lpapplicationname,
Lptstr lpcommandline,
Lpsecurity_attributes lpprocessattributes,
Lpsecurity_attributes lpthreadattributes,
Bool binherithandles,
DWORD dwcreationflags,
Lpvoid lpenvironment,
Maid directory,
Lpprocess_information lpprocessinformation


Lpapplicationname points to a string containing the name of the module to be run.
Lpcommandline points to the command line string.
Lpprocessattributes describes the security attributes of a process. It is useful in NT.
Lpthreadattributes describes the security attributes of the initial process thread (main thread), which is useful in NT.
Binherithandles indicates whether a child process (the created process) can inherit the handle of the parent process. The handhandles that can be inherited include thread handles, famous or unknown pipelines, mutex objects, events, semaphores, image files, common files, and communication ports. Some handles cannot be inherited, such as memory handle, DLL instance handle, GDI handle, and urer handle.

The handle inherited by a child process is transmitted to the parent process by the parent process through command line or inter-process communication (IPC.

Dwcreationflags indicates the priority category and process type of the created process. The Process Creation type is divided into console process and debugging process. The priority type is used to control the priority level of the process, including idle, normal, high, and real_time.

Lpenviroment points to the environment variable block, which can be inherited by the quilt process.
The lpcurrentdirectory points to the string indicating the current directory. The current directory can be inherited.
Lpstartupinfo points to the startupinfo structure to control the appearance of the Main Window of the process.
Lpprocessinformation points to the process_information structure to store the returned process information.

The parameters show what information needs to be specified to create a new process.

From the above explanation, we can see that a process contains a lot of information. If the process is successfully created, a pointer to the process information structure is returned. The process information structure is as follows:

Typedef struct _ process_information {
Handle hprocess;
Handle hthread;
DWORD dwprocessid;
DWORD dwthreadid;
} Process_information;

The process information structure includes the Process Handle, Master thread handle, process ID, and Master thread ID.

Process Termination

The process is terminated in the following circumstances:

    • Call exitprocess to end the process;
    • The main thread of the process returns, implicitly calling exitprocess causes the process to end;
    • The last thread of the process is terminated;
    • Call terminateprocess to terminate the process.

To end a GDI process, send the wm_quit message to the main window. You can also call exitprocess from any of its threads.

Win32 thread

Thread Creation

Use the createthread function to create a thread. The createthread prototype is as follows:

Handle createthread (
Lpsecurity_attributes lpthreadattributes,
DWORD dwstacksize,
Lpthread_start_routine lpstartaddress,
Lpvoid lpparameter,
DWORD dwcreationflags, // creation flags
Lpdword lpthreadid


Lpthreadattributes indicates the Security Attribute of the created thread, which is useful in NT.
Dwstacksize specifies the size of the thread stack. If it is 0, it is the same as the main thread stack of the process.
Lpstartaddress specifies the address at which the thread starts running.
Lpparameter indicates the 32-bit parameter passed to the thread.
Dwcreateflages indicates whether to suspend the thread after creation (value: create_suspend). After suspension, call resumethread to continue execution.
Lpthreadid is used to store the returned thread ID.

Thread priority

Each priority class of a process contains the priority levels of five threads. After the priority class of the process is determined, the priority level of the thread can be changed. Set the process priority class with setpriorityclass and set the thread priority level with setthreadpriority.

Normal threads can be preemptible by any thread except idle.

Thread termination

Terminate a thread in the following cases:

    • The exitthread function is called;
    • Thread function return: the return of the main thread causes the exitprocess to be called, and the return of other threads causes the exitthread to be called;
    • Calling exitprocess causes all threads of the process to terminate;
    • Call terminatethread to terminate a thread;
    • When terminateprocess is called to terminate a process, all its threads are terminated.

When terminateprocess or terminatethread is used to terminate a process or thread, the DLL entry function dllmain is not executed (if a dll exists ).

Local thread storage

If you want each thread to have static data stored locally, you can use the TLS Thread Local storage technology. TLS assigns a TLS index to the process. Each thread of the process uses this index to access copies of its own data variables.

TLS is very useful for DLL. When a new process uses DLL, use tlsalloc In the DLL entry function dllmain to allocate TLS indexes. The TLS indexes are saved as private global variables of the process, when the new thread of the process uses DLL (attahced to DLL), dllmain allocates dynamic memory to it and uses tlssetvalue to store the private data of the thread by index. DLL functions can use tlsgetvalue to read private data of the calling thread by index.

The TLS function is as follows:

DWORD tlsalloc ()

It is called during process or DLL initialization and the return value (index value) is saved as a global variable.

Bool tlssetvalue (
DWORD dwtlsindex, // TLS index to set value
Lpvoid lptlsvalue // value to be stored

Dwtlsindex is the index allocated by tlsalloc.
Lptlsvalue is the Data Pointer stored by the thread in the TLS slot, pointing to the data to be saved by the thread.

The thread first allocates dynamic memory and saves data to the memory, and then calls tlssetvalue to save the memory pointer to the TLS slot.

Lpvoid tlsgetvalue (
DWORD dwtlsindex // TLS index to retrieve value


Dwtlsindex is the index allocated by tlsalloc.

When you want to access the stored data, use the index to get the data pointer.

Bool tlsfree (
DWORD dwtlsindex // TLS index to free


Dwtlsindex is the index allocated by tlsalloc.

When each thread no longer uses local data storage, the thread releases the dynamic memory it allocates. When TLS indexes are no longer needed, use tlsfree to release the indexes.

Thread Synchronization

Synchronization ensures that only one thread has control over a resource (such as operating system resources and other shared resources) within a period of time. Shared resources include global variables, public data members, and handles. Synchronization also enables code with associated interactions to be executed in a certain order.

Win32 provides a set of objects for multi-thread synchronization.

These objects have two states: signaled or not signaled ). The thread uses the synchronous wait function (wait functions) provided by the Win32 API to use the synchronization object. A synchronous object is specified when the synchronous wait function is called. The thread that calls the synchronous function is blocked until the synchronous object obtains the signal. The blocked thread does not occupy the CPU time.

Synchronization object

Synchronization objects include: critical_section (key segment), event, mutex, and semaphores ).

The following explains how to use these synchronization objects.

Key segment object:

First, define a key segment object Cs:

Critical_section Cs;

Then, initialize the object. Set the object to not_singaled during initialization to allow the thread to use resources:

Initializecriticalsection (& CS );

If a piece of program code needs to synchronize and protect a certain resource, this is a key piece of code. Call the entercriticalsection function before entering the key code segment. In this way, no other thread can execute the code segment. If they attempt to execute the code segment, they will be blocked.

After the key segment is executed, call the leavecriticalsection function, and other threads can continue to execute the code segment. If this function is not called, other threads will wait indefinitely.

Event object

First, call the createevent function to create an event object, which returns an event handle. You can set (setevent) or reset (resetevent) an event object, or send an event pulse (plusevent) to set an event object and reset it. There are two methods to reset: automatic reset and manual reset. Specify the reset form when creating the event object ..

Automatic Reset: when the object receives a signal, it will release the next available thread (the highest priority thread; if the priority level is the same, it will wait for the first thread in the queue to be released ).

Manual reset: when an object obtains a signal, all available threads are released.

Finally, use closehandle to destroy the created event object.

Mutex object

First, call createmutex to create a mutex object. Then, call the wait function to use key resources. Finally, call realsemutex to release the mutex object.

Mutex objects can be used between processes, but key segment objects can only be used between threads of the same process.


In Win32, when the semaphore value is 0, a signal is given. You can use a semaphore object when multiple resources need to be managed.

First, call createsemaphore to create a semaphore. Then, call the wait function to use key resources if allowed. Finally, call realeasesemaphore to release the semaphore object.

In addition, there are other handles that can be used to synchronize threads:

    • File handles)
    • Named Pipe handle (Named Pipe Handels)
    • Console input buffer handle)
    • Communication device handle (Communiction device handles)
    • Process handles)
    • Thread handles)

For example, when a process or thread ends, the process or thread handle gets a signal and the thread waiting for the process or thread to end is released.

Wait Function

Win32 provides a set of wait functions for a thread to block its own execution. Wait functions are divided into three types:

Waiting for a single object ):

Such functions include:




Function parameters include the synchronization object handle and wait time.

Wait for the function to return in the following cases:

Returned when the synchronization object obtains the signal;

Return when the wait time reaches: If the wait time is not limited (infinite), only the synchronization object obtains the signal to return; if the wait time is 0, then return immediately after testing the synchronization object status.

Waiting for multiple objects (for multiple objects)

Such functions include:





Function parameters include the synchronization object handle, wait time, whether to wait for one or more synchronization objects, and so on.

Wait for the function to return in the following cases:

Return when one or all synchronization objects receive signals (in the parameter, it must be waiting for one or more synchronization objects );

Return when the wait time reaches: If the wait time is not limited (infinite), only the synchronization object obtains the signal to return; if the wait time is 0, then return immediately after testing the synchronization object status.


Such functions include:





These functions are mainly used for overlapping I/O (asynchronous I/O ).

MFC thread processing

Based on the Win32 API, MFC provides classes and functions for processing threads. The class for processing threads is cwinthread, and the function is afxbeginthread and afxendthread.

Table 5-6 explains the member variables and functions of cwinthread.

Cwinthread is an MFC Thread class. Its member variables m_hthread and m_hthreadid are the corresponding Win32 thread handle and thread ID.

MFC clearly distinguishes two threads: User Interface thread and worker thread ). User Interface threads are generally used to process user input and respond to user-generated events and messages. The worker thread is used to complete tasks that do not require user input, such as time-consuming computing.

Win32 API does not differentiate thread types. It only needs to know the thread start address so that it can start to execute the thread. MFC provides message pumps for user interface threads to process user interface events. A cwinapp object is an example of a user interface thread object. cwinapp derives from a class cwinthread and processes user-generated events and messages.

Create user interface thread

Follow these steps to create a user interface thread:

A class with dynamic creation capability is derived from cwinthread. Use the declare_dyncreate and implement_dyncreate macros to support dynamic creation.

Some virtual functions of cwinthread are covered. The functions that can be covered are shown in Table 5-4 about cwinthread. The initinstance function must be overwritten, and exitinstance is usually overwritten.

Use afxbeginthread to create the MFC thread object and Win32 thread object. If create_suincluded is not specified during thread creation, the execution thread starts.

If create_suincluded is specified for the Creation thread, call the resumethread function in the appropriate place to start the execution thread.

Create a worker thread

Programmers do not have to derive a new Thread class from cwinthread. They only need to provide a control function, which is executed after the thread starts.

Then, use afxbeginthread to create the MFC thread object and Win32 thread object. If create_suincluded (suspended after creation) is not specified during thread creation, the newly created thread starts execution.

If create_suincluded is specified for the Creation thread, call the resumethread function in the appropriate place to start the execution thread.

Although programmers do not derive classes from cwinthread, MFC provides the worker thread with the default cwinthread object.


Both the user interface thread and worker thread are created by afxbeginthread. Now, test the function: MFC provides two overloaded versions of afxbeginthread, one for the user interface thread and the other for the worker thread, which has the following prototype and process:

Afxbeginthread of the user interface thread

The afxbeginthread prototype of the user interface thread is as follows:

Cwinthread * afxapi afxbeginthread (

Cruntimeclass * pthreadclass,

Int npriority,

Uint nstacksize,

DWORD dwcreateflags,

Lpsecurity_attributes lpsecurityattrs)


Parameter 1 is the runtime_class class derived from cwinthread;

Parameter 2 specifies the thread priority. If it is 0, it is the same as the thread that created the thread;

Parameter 3 specifies the thread stack size. If it is 0, it is the same as the thread that created the thread;

Parameter 4 is a creation identifier. If it is create_suincluded, a thread is created in the suspension state, and the thread is suspended after the thread is created. Otherwise, the thread starts executing after the creation.

Parameter 5 indicates the thread security attribute, which is useful in NT.

Afxbeginthread of the worker thread

The prototype of afxbeginthread of the worker thread is as follows:

Cwinthread * afxapi afxbeginthread (
Afx_threadproc pfnthreadproc,
Lpvoid pparam,
Int npriority,
Uint nstacksize,
DWORD dwcreateflags,
Lpsecurity_attributes lpsecurityattrs


Parameter 1 specifies the address of the control function;
Parameter 2 specifies the parameter passed to the control function;
Parameters 3, 4, and 5 respectively specify the thread priority, stack size, creation ID, and security attributes, meaning the same as the user interface thread.

Afxbeginthread thread creation process

No matter which afxbeginthread, the first is to create an MFC thread object, and then create a Win32 thread object. When you create an MFC thread object, different constructors are called for the creation of user interface threads and worker threads. The User Interface thread is derived from cwinthread. Therefore, you must first call the default constructor of the derived class and then call the default constructor of cwinthread. In Figure 8-1, the commonconstruct called by the two constructors is a member function used inside MFC.

Createthread and _ afxthreadentry

MFC uses cwinthread: createthread to create a thread. Whether it is a worker thread or user interface thread, the thread entry function is _ afxthreadentry. _ Afxthreadentry calls the afxinitthread initialization thread.

Createthread and _ afxthreadentry use synchronous means to interactive waiting and execution during thread creation. Createthread is executed by the creation thread, and _ afxthreadentry is executed by the created thread. The two are synchronized through two event objects (hevent and hevent2:

After a new thread is created, the creation thread will wait infinitely on the hevent event until the new thread gives the creation result. After the new thread is created successfully or fails, the hevent event is triggered to run the parent thread, in addition, heven2 waits infinitely until the parent thread exits the createthread function. The parent thread (creation thread) waits until the hevent's position ends and continues execution. hevent2 is triggered before the createthread is exited; the new thread (subthread) starts to execute the control function (worker thread) or enters the message loop (User Interface thread) Because hevent2 is set to an end wait ).

The following data structure is used in the MFC online creation:

Struct _ afx_thread_startup


// Parameters passed to the thread startup (in)

_ Afx_thread_state * pthreadstate; // The thread status of the parent thread

Cwinthread * pthread; // the newly created MFC thread object

DWORD dwcreateflags; // ID created by the thread

_ PNH pfnnewhandler; // handle of the new thread

Handle hevent; // synchronization event. The rear position of the thread that is successfully created or fails to be created

Handle hevent2; // synchronization event. The new thread resumes the execution of the rear position.

// Return the parameter to the thread to be created, which is assigned a value after the new thread resumes execution.

Bool berror; // true if an error occurs during creation


This structure is passed to the _ beginthreadex function as a parameter of the thread start function to create and start the thread. The _ beginthreadex function is a "C" thread creation function with the following prototype:

Unsigned long _ beginthreadex (

Void * security,

Unsigned stack_size,

Unsigned (_ stdcall * start_address) (void *),

Void * Arglist,

Unsigned initflag,

Unsigned * thrdaddr );

Figure 8-2 describes the preceding process. The figure shows that when _ afxthreadentry starts a thread, it will create the thread status of the thread and inherit the module status of the parent thread. For more information about the status of MFC, see Chapter 9th.

End of Thread

As shown in Figure 8-2, afxendthread is used to end the thread that calls it: it cleans up the MFC object created by this thread and releases the memory space allocated by the local storage of the thread; it calls the cwinthread virtual function Delete; call the end thread function _ endthreadex of "C" to release the resources allocated to the thread, but do not close the thread handle.

Cwinthread: The default Implementation of Delete is: if the member function m_bdelete in this thread is true, call the "c" operator "Delete to destroy the MFC thread object itself (delete this ), this will cause the destructor of the thread object to be called. If the Destructor detects that the thread handle is not empty, call closehandle to disable it.

Generally, set m_bdelete to true to automatically destroy the thread object and release the memory space (the MFC memory object is allocated in the heap ). However, sometimes it is useful to retain the MFC thread object after the thread ends (the Win32 thread does not exist). Of course, the programmer should remember to destroy the thread object at last.

Implement thread message loop

In MFC, message loops are completed by threads. Generally, you can use the default message loop of MFC (that is, the function cwindthrad: Run). However, sometimes the programmer needs to implement a thread message loop by himself, for example, when the user interface thread performs a long computing process or waits for another thread. Generally, there are the following forms:

While (bdoingbackgroundprocessing)



While (: peekmessage (& MSG, null, 0, 0, pm_noremove ))


If (! Pumpmessage ())


Bdoingbackgroundprocessing = false;

: Postquitmessage ();




// Let MFC do its idle Processing

Long role Le = 0;

While (afxgetapp ()-> onidle (role le ++ ));

// Perform some background processing here

// Using another call to onidle


For more information about the code in this section, see Figure 5-3.

There are two advantages for programmers to implement the message loop of threads. One is to take into account the idle Processing Mechanism of MFC; the other is to respond to user-generated events or messages during a long period of processing.

You can use the same method when waiting for other threads on the synchronization object.


In the following format:

Waitforsingobject (hhandleofevent, 0) = wait_timeout

You can.

When processing threads and processes, MFC also introduces an important concept: State, such as thread state, process state, and module state. This concept plays an important role in MFC and involves a lot of content, so we will talk about it in the next chapter.

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: 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.