Multithreaded Programming Essentials __ Programming

Source: Internet
Author: User
Tags bool function prototype mutex reset semaphore terminates thread class win32
A thread is an execution path to a process that contains independent stacks and CPU register states, each of which shares all of the process resources, including open files, signal identities, and dynamically allocated memory. All threads within a process use the same address space, and the execution of those threads is controlled by the system scheduler, which determines which thread is executable and when it executes the thread. Threads have priority, and lower priority threads must wait until the higher priority thread finishes executing. On multiprocessor machines, the scheduler can put multiple threads on different processors to run, which can balance the processor tasks and improve the efficiency of the system.

Windows is a multi-tasking operating system that contains one or more threads within a process in Windows. The Win32 API in a 32-bit Windows environment provides the interface functions required for multithreaded application development, while the standard C library provided in the VC can also be used to develop multithreaded applications, and the corresponding MFC class libraries encapsulate classes of multithreaded programming. The user can choose the appropriate tool according to the needs and characteristics of the application when developing. In order to enable everyone to fully understand the Windows multithreaded programming technology, this article will focus on the WIN32 API and MFC two ways of how to develop multithreaded programs.

The principle of multithreaded programming is consistent with the support of the MFC class Library in WIN32 mode, and the main thread of the process can create new threads whenever needed. Automatically terminates the thread when the thread finishes executing; When the process is finished, all threads are terminated. All active threads share the resources of the process, so when programming you need to consider the issue of conflicts when multiple threads access the same resource. When a thread is accessing a process object, and another thread is changing the object, it can produce incorrect results and resolve the conflict when programming.

Multithreaded programming under the Win32 API

The Win32 API is the interface between the Windows operating system kernel and the application, which wraps the functions provided by the kernel, and the application obtains the corresponding system functions by invoking the relevant functions. In order to provide multithreaded functionality to applications, the WIN32 API function sets the set of functions that handle multi-threaded programs. Programming directly with the WIN32 API has many advantages: WIN32-based application execution is small and efficient, but it requires programmers to write more code and to manage the resources that all systems provide to the program. Programming directly with the WIN32 API requires programmers to have a good understanding of the Windows system kernel, which takes a lot of time to manage system resources, thus reducing programmer productivity.

1. Creating and terminating threads with the WIN32 function

The WIN32 function library provides functions to manipulate multithreading, including creating threads, terminating threads, establishing mutex zones, and so on. The function to create a new thread in the main thread of the application or in another active thread is as follows:

HANDLE CreateThread (lpsecurity_attributes lpthreadattributes,dword dwstacksize,lpthread_start_routine Lpstartaddress,lpvoid Lpparameter,dword Dwcreationflags,lpdword Lpthreadid);

Returns a handle to the thread if creation succeeds, otherwise null is returned. When a new thread is created, the thread starts executing. But if the create_suspended feature is used in dwCreationFlags, then the thread does not execute immediately, but hangs first, waits until the resumethread is called before starting the thread, and in this process can call the following function to set the priority of the thread:

BOOL setthreadpriority (HANDLE hthread,int npriority);

When the calling thread's function returns, the thread terminates automatically. The function can be called if it needs to be terminated during the execution of the thread:

VOID ExitThread (DWORD dwexitcode);

If the thread is terminated outside the threads, the following function can be called:

BOOL TerminateThread (HANDLE hthread,dword dwexitcode);

It should be noted, however, that this function may cause system instability and that the resources used by the thread will not be freed. Therefore, it is generally not recommended to use this function.

If the thread to be terminated is the last thread in the process, the corresponding process should also terminate after the thread is terminated.

2. Synchronization of Threads

In the thread body, if it is completely independent and conflicts with other threads that do not have resource operations such as data access, it can be programmed in a normally single-threaded way. However, this is often not the case with multithreading, where the threads often have to access some resources at the same time. Since access to shared resources is unavoidable, in order to resolve this thread synchronization problem, the Win32 API provides a variety of synchronization control objects to help programmers resolve shared resource access violations. Before introducing these synchronization objects, let's introduce the wait function, because the function is used for all control object access control.

The Win32 API provides a set of wait functions that enable a thread to block its own execution. These functions produce a signal in one or more of the synchronization objects in their arguments, or exceed the specified wait time to return. When the wait function is not returned, the thread is in a wait state, and the thread consumes very little CPU time. Using the wait function can not only guarantee the synchronization of threads, but also improve the running efficiency of the program. The most common wait functions are:

DWORD WaitForSingleObject (HANDLE hhandle,dword dwmilliseconds);

The function Waitformultipleobject can be used to simultaneously monitor multiple synchronization objects, which are declared as:

DWORD Waitformultipleobject (DWORD ncount,const HANDLE *lphandles,bool Bwaitall,dword dwmilliseconds);

(1) Mutex object

The state of a mutex object is signaled when it is not owned by any thread, and no signal when it is owned. A mutex object is ideal for reconciling multiple threads with mutually exclusive access to shared resources. You can use this object by following these steps:

First, create the mutex object and get the handle:

HANDLE CreateMutex ();

Then, before the thread can produce a conflicting zone (that is, before accessing the shared resource), call WaitForSingleObject, pass the handle to the function, and request the mutex object:

Dwwaitresult = WaitForSingleObject (hmutex,5000l);

End of shared resource access, freeing up the use of mutex objects:

ReleaseMutex (Hmutex);

A mutex object can only be occupied by one thread at a time, and when a mutex object is occupied by one thread, if there are other threads that want to occupy it, it must wait until the previous thread is released before it succeeds.

(2) Signal object

The signal object allows access to multiple threads sharing resources at the same time, specifying the maximum number of threads that can be accessed concurrently when the object is created. When a thread requests a successful access, the counter in the signal object is reduced by one, and after the ReleaseSemaphore function is called, the counter in the signal object is incremented by one. Where the counter value is greater than or equal to 0, but less than or equal to the maximum value specified at the time of creation. If an application creates a signal object, the initial value of its counter is set to 0, blocking other threads and protecting the resource. When initialization is complete, call the ReleaseSemaphore function to increase its counter to the maximum value for normal access. You can use this object by following these steps:

First, create the signal object:

HANDLE CreateSemaphore ();

or open a Signal object:

HANDLE OpenSemaphore ();

Then, the thread accesses the shared resource before calling WaitForSingleObject.

When access to a shared resource is complete, the usage of the semaphore object should be released:

ReleaseSemaphore ();

(3) Event object

The event object is the simplest synchronization object, which consists of both signaled and no-signal states. Before a thread accesses a resource, it needs to wait for an event to occur, which is most appropriate for the event object. For example, the monitoring thread is activated only after the data is received by the communication port buffer.

The event object is built with the CreateEvent function. The function can specify the class of the event object and the initial state of the event. If the event is manually reset, it will always remain signaled until the ResetEvent function is reset to a signal-free event. If the event is automatically reset, its state will automatically become non-signaled when a single waiting thread is released. The event object can be set to a signal state using SetEvent. When an event is established, you can name the object so that threads in other processes can open the event object handle of the specified name with the OpenEvent function.

(4) object of exclusion zone

When executed asynchronously in an exclusion zone, it can only share resource processing between threads in the same process. Although several of the methods described above can be used at this point, the use of exclusion zones makes synchronization management more efficient.

When used, a critical_section object is defined, and the object is initialized with the following function before the process is used:

VOID initializecriticalsection (lpcritical_section);

When a thread uses the exclusion zone, the function is called: EnterCriticalSection or tryentercriticalsection;

Call the function leavecriticalsection when it is required to occupy and exit the exclusion zone, freeing the object from the exclusion zone for use by other threads.

Multi-threaded programming based on MFC

MFC is a library of basic functions provided to programmers in the context of Microsoft's VC development integration, which encapsulates the Win32 API in a class library and provides it to developers in a class way. Because of its fast, simple, powerful features and so on by the vast number of developers love. Therefore, it is recommended that you use the MFC class library for application development.

In the MFC class library that comes with VC + +, it provides support for multithreading programming, the basic principle is consistent with the design based on Win32 API, but because MFC encapsulates the synchronization object, it is more convenient to implement and avoids the tedious work of object handle management.

In MFC, there are two types of threads: Worker threads and user interface threads. The worker thread is consistent with the thread described earlier, and the user interface thread is a thread that can receive input from the user, handle events, and messages.

1. Worker Threads

Working thread programming is simpler, and the design idea is basically the same as before: A basic function represents a thread, and after the thread is created and started, the thread goes into a running state; If the thread is using a shared resource, resource synchronization is required. This way you can call a function when you create a thread and start a thread:

Cwinthread*afxbeginthread (Afx_threadproc pfnthreadproc, lpvoid pparam,int npriority= THREAD_PRIORITY_NORMAL,UINT Nstacksize =0,dword dwcreateflags=0, lpsecurity_attributes lpsecurityattrs = NULL), the parameter pfnthreadproc is the thread execution body function, the function prototype is: UINT threadfunction (LPVOID pparam).

The parameter pparam is the argument passed to the execution function;

The parameter npriority is the thread execution permission, optional value:

Thread_priority_normal, Thread_priority_lowest, Thread_priority_highest, Thread_priority_idle.

The parameter dwcreateflags is a thread-creation flag, a value of create_suspended that indicates that the thread was created in a pending state, the thread continues to run after the ResumeThread function is called, or a value of "0" indicates that the thread was created and is in a running state.

The return value is a CWinThread class object pointer, its member variable m_hthread is a thread handle, and the function arguments to the thread operation in Win32 API are required to provide a handle to the thread, so when the thread is created, all WIN32 API functions can be used to pwinthread- The >m_thread thread is related to the operation.

Note: If you create and start a thread in a class object, you should define the thread function as a global function outside the class.

2. User interface Threads

An MFC-based application has an Application object, which is an object of the CWinApp derived class that represents the main thread of the application process. When the thread finishes executing and exits the thread, the process automatically ends because no other threads exist in the process. The class CWinApp is derived from CWinThread and CWinThread is the basic class of the user interface thread. When we write the user interface thread, we need to derive our own thread class from CWinThread, and ClassWizard can help us with this work.

First derive a new class with ClassWizard and set the base class to CWinThread. Note: The Declare_dyncreate and implement_dyncreate macros of the class are required because the objects of the class need to be created dynamically when the thread is created. The initialization and closing code can be placed in the InitInstance and ExitInstance functions of the class, as needed, respectively. If you need to create a window, you can do so in the InitInstance function. Then create the thread and start the thread. There are two ways to create a user interface thread, and MFC provides two versions of the AfxBeginThread function, one of which is used to create a user interface thread. The second approach is in two steps: First, the constructor of the thread class is called to create a thread object, and second, the CWinThread::CreateThread function is called to create the thread. After the thread is established and started, the threads function executes during execution. If it is a thread object, the thread is ended before the object is deleted. CWinThread has completed the thread-end work for us.

3. Thread synchronization

Before we introduced the Win32 API provides several kinds of thread synchronization objects, in the MFC class library of these objects are class encapsulated, they have a common base class CSyncObject, their correspondence is: semaphore corresponding CSemaphore, The mutex corresponds to the CMutex, the event corresponds to the CEvent, and criticalsection corresponds to CCriticalSection. In addition, MFC encapsulates two wait functions, namely CSingleLock and CMultiLock. As the four object usages are similar, here is an example of CMutex:

Create a CMutex object:

CMutex Mutex (false,null,null);

or CMutex mutex;

Use the following code when each thread accesses a shared resource:

CSingleLock SL (&mutex);

Sl. Lock ();

if (SL. IsLocked ())

Working with shared resources ...

Sl. Unlock ();

Conclusion

Using multithreading is an ideal choice if the user's application requires multiple tasks to be processed at the same time. Here, it is important to note that in multithreaded programming, special care should be taken to deal with the problem of resource sharing and multi-threaded debugging.

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.