Apply multithreading in the .NET client program.

zhaozj2021-02-17  39

Apply Multi-threaded original in .NET client program: Jason Clark Translation: lxhui

Original Source: MSDN Magazine Jan 2004 (.NET) Original Code Download: Net0401.EXE (118KB) is usually considered to use multithreading in writing programs to be a senior programming task, which is easy to happen. In this month's column, I will use multithreading in a Windows® form application, which is actually meaningful, and try to make things simple. My goal is to explain multi-thread in an ordinary demand description; customers still prefer applications that make user interactive. Multi-threaded usually links with server-side software, scalability, and performance technology. However, in the Microsoft .NET framework, many server-side applications reside in the ASP.NET architecture. Similarly, these applications are logically single-threaded because IIS and ASP.NET perform a lot of or all multi-threads in the ASP.NET Web Form or Web service. You typically ignore threads in the ASP.NET application. That's why in the .NET framework, multi-thread is more inclined to use in the client, such as performing a long action while ensuring the interaction with the user. Thread background thread execution code. They are implemented by the operating system and is an abstraction of the CPU itself. Many systems have only one CPU, and threads are separated by the speed of the CPU to perform multiple operations, so that they look like synchronous. Even if a system is made of multiple CPUs, the running thread is generally more than the processor. In a Windows-based application, each process must have a thread that can perform machine language instructions. Once all threads in a process are aborted, the process itself and the resources it occupies will be cleared by Windows. Many applications are designed as a single-threaded program, which means that the process implemented by the program never performs more than one thread, even in the system, there are multiple same processing. Generally, a process does not care about the execution of threads in other processes in the system. However, all threads in a single process not only share virtual address space, but also many process-level resources are shared, such as files and window handles. Due to the feature of the process resource sharing, a thread must consider what other threads doing in the same process. Thread synchronization is an art that maintains each thread mutually unable conflict in a multi-thread process. This also makes multi-threaded difficulties. The best way is to use multithreading only when needed, try to keep things simple. And avoid thread synchronization. In this column, I will show you how to do these things for an ordinary customer app. Why use multiple threads? There are already many single-threaded client applications, and there are many written a day. In many cases, the behavior of a single thread is sufficient. However, add some asynchronous behaviors in some specific applications to improve your experience. Typical database front-end programs are a good example. Database query takes a lot of time to complete. In a single-threaded application, these queries cause the Window message processing capability to block, resulting in the user interaction of the program to be frozen. Solution is that this I will have to describe in detail, using a thread to handle messages from the operating system, and another thread makes a long work. Important reasons for using the second thread in your code is that even if there is a busy job behind the scenes, it is also necessary to guarantee the user's interaction of your program. Let's take a look at a single-threaded GUI program that is long-operated. Then we will use additional threads to organize the program. Figure 1 is a complete source code for a program written by C #. It creates a form with a text box and a button. If you type a number in the text box, then press the button, this program will handle the number you entered, which represents the number of seconds, and the bell represents the processing of the background once a second. In addition to Figure 1's code, you can download the full code from the link starting in this article.

Download or type the code shown in Figure 1, compile it before reading, (Before compiling, right-click your project in Visual Studio.net, join Microsoft Visual Basic Runtime) When you try to run the SingLethReadedformed in Figure 1 When the .cs application, you will see a few questions immediately. When you first test run, enter 20 in the text box, press the button. You will see the user interaction of the program has not responded at all. You can't click on the button or edit the text box, the program cannot be closed, if you override the form next to the part of the window, it will no longer redraw yourself (see Figure 2), this program is locked It is 20 seconds, but it can continue to ring, prove that it has not really dead. This simple program explains the problem of single-threaded GUI program. I will use multithreading to solve the first question: I have interacted users, but first, I will explain what this phenomenon. Threads and Windows User Interface The Windows Forms library is based on the USER32 WIN32 API well known. User32 implements the basic elements of the GUI, such as forms, menus, and buttons. All forms driven structures are used by all forms and controls implemented by the USER32. It is simple to talk about how they work. Things that happen on the form, such as the mouse click, coordinate change, size change, and redraw requests, are called events. Events in the USER32 API model are represented by the form message. Each form has a function called window procedure or WNDPROC, which is implemented by an application. WndProc is responsible for processing form messages for the form. But WndProc is not a magical call. Instead, the application must call GetMessage to actively get a form message from the system. This message is assigned to the WndProc method of their target form being called the DispatchMethod API method. The application is just a simple loop reception and allocation window message, which is generally called a message pump or message loop. Threads have all forms so that it can extract messages, and the WndProc function is also called by the same thread. Go back to the Windows Forms class now. Windows Forms performs approximately 95% of the Message structure of the USER32 in the application. Instead of the WNDPROC function, the Windows Forms program defines the event processor and virtual function overload to process different system events related to the form (window) or control. However, the message extraction must be running, it is implemented in the Application.Run method of the Windows Forms API. The code shown in Figure 1 seems to only call Application.run then exit. However, this lacks transparency: the primary thread of the application is only a call to Application.Run in its lifecycle, but the result is a call for different event processors for other parts of the application. When the button on the form is clicked, the OnClick method in Figure 1 is called by the primary thread, which is also responsible for extracting messages in Application.run. This explains why the user interacts in response when a long operation occurs. If a long action in an event processor (such as database query) occurs, then the main thread is occupied, it needs to be continuously extracted. There is no ability to extract the message and send it to a window or form, there is no ability to respond to adjust the size, redraw yourself, handle any interactions, or respond to any interaction. In the next section, in order to perform a long operation I will use the thread pool at the public language to modify the example code shown in Figure 1, so the main thread can still extract the message.

The hosted thread CLR maintains a thread pool for each managed process, which means that when your application main thread needs to perform some asynchronous processing, you can easily achieve specific processing from a thread in a thread. . Once the processing is completed, the thread is returned to the thread pool for future use. Let us look at an example and modify the use of thread pools. Note that the row represents the red part of FlawmultithreadForm.cs in Figure 3; they are the only code to modify when the single-line scheme in Figure 1 is multithreaded. If you compile the code shown in Figure 3, set it for 20 seconds, you will see the user's interaction when you process 20 bells. Use multi-thread in the client program to respond to user interaction is an attractive reason. However, in Figure 3 changes, a new problem is introduced (like the name of Figure 3); now the user can start multiple simultaneous operations. This can cause conflicts between threads in many real-time applications. In order to correct this thread synchronous request, I will tell these, but first familiar with the CLR '' '' s thread pool. The System.Threading.ThreadPool class in the class library provides an API interface to access the CLR '' '' s thread pool. The ThreadPool type cannot be instantiated, which consists of static members. The most important way for threadpool types is two overloads for ThreadPool.QueueUserWorkItem. Both methods let you define a function that you are willing to be called by a thread in the thread pool. Define your method by using an instance of the WaitCallback entrustment type in the class library. An overload allows you to define a parameter for asynchronous methods; this is the version used by Figure 3. The following two lines of code create a commission instance, representing a count method, the next call queuing waiting for the method in the thread pool. Waitcallback async = New Waitcallback (count);

Threadpool.queueUserWorkItem (async, count);

ThreadPool.QueueUserWorkItem two methods let you define an asynchronous callback method in the queue and return it immediately. At the same time, the thread pool monitors this queue, then lists the methods, and uses one or more threads in the thread pool to call the method. This is the main usage of the CLR '' '' s thread pool.

The CLR '' '' s thread pool is also used by other APIs of the system. For example, the system.threading.timer object will wait in the thread pool in the thread pool at the thread pool. Threadpool.registerwaitforsingleObject method queues waiting in the thread pool when responding to the kernel system synchronization object. Finally, the callback is executed by different asynchronous methods in the class library, which is performed by the CLR '' 'S-Pool.

In general, an application only requires a multi-thread for a simple asynchronous operation, there is no doubt that should use the thread pool. Compare a thread object, this method is recommended. Call ThreadPool.QueueUserWorkItem can perform simple and manually created a thread relative to repeated manual creation threads.

The simplest thread synchronization

At this column, I will say that keep thread synchronization without mutual conflict is an art.

The FlawedMultithreadForm.cs app shown in Figure 3 has a problem: users can trigger a long ring operation by clicking the button, they can continue click the button to lead more ringing operations. If it is not a bell, the long operation is a database query or a data structure operation in the process of the process. You must not want to have more than one thread in the same time. Best case, this is a waste of system resources, the worst case, will result in data destruction. The easiest solution is to prohibit user interaction elements of a class of buttons; communication between the two processes is slightly difficult. After a while, I will show you how to do these things. But first, let me point out some of the threads in which all threads are synchronized - a means of communicating from a thread to another thread. I will discuss the type of AutoreteEvent object known to everyone, which is only used inter-threads.

Let us first look at it now

The thread synchronization code added to the FlawedmultithReadedForm.cs program in FIGURE 3. again,

The red portion in the Figure 4 CorrectMultithreadedform.cs program is represented by the smaller change in the previous program. If you run this program you will see that the user interaction is banned when a long ring operation is prohibited (but not hang), and it is allowed when the ring is completed. This change in this code is enough, I will run them one by one.

in

There is an enablecontrols from the end of Figure 4, which allows or disables text boxes and button controls on the form. in

The beginning of Figure 4 I added an enablecontrols called, and the text box and button were prohibited immediately before the background bell operation queued. The synchronization of threads here has been completed, because users are prohibited from interacting, so users cannot trigger more background conflicts operations. in

The end of Figure 4 will see a delegate type named BooleanCallback is defined whose signature is compatible with the EnableControls method. Before that definition, a delegate domain named EnableControls is defined (see example), which references the EnableControls method of the form. This entrusted domain is assigned in the beginning of the code.

You will also see a callback from the primary thread that owns and extracts messages for the form and its controls. This call enables controls by passing a TRUE parameter to EnableControls. This is done by the INVOKE method of the background thread, which is completed once it is completed. The credit reference of the code delivery reference EnableControls goes invoke, the parameters of this method come with an array of objects. The Invoke method is a very flexible way of communication between threads, especially for windows or forms in the Windows Forms library. In this example, INVOKE is used to tell the main GUI thread to re-enable controls on the form by calling the EnableControls method.

The change in CorrectMultithreadedForm.cs in Figure 4 achieves my earlier suggestion - when the ring is executed, you don't want to run, prohibit the user interaction of the ringing operation. When the operation is complete, tell the main thread to re-enable the part of the disabled. The call to Invoke is unique, this should be noted.

Invoke method is defined in the System.Windows.Forms.Controls type, which contains all derived controls in the form library to use this method. The purpose of the Invoke method is to configure a call from any thread to implement a message to form a message for a form or control.

When accessing the control derive class, including the FORM class, you must do this from the thread of the extraction control message. This is a natural thing in a single-threaded application. But when you use multiple threads from the thread pool, avoid the method and attributes of calling the user interactive object from the background thread. Instead, you must access them indirectly using the control of the INVOKE method. Invoke is a rare method that can be securely called safe from any thread because it is implemented with Win32 PostMessage API. Communication between the thread room with the Control.Invoke method is a bit complicated. But once you are familiar with this process, you have tools that implement multithreaded targets in your client program. The remainder of this column will overwrite some other details, but

The CorrectMultithReadedForm.cs app in Figure 4 is a complete solution: Other operations can still be responded when performing any long operation. Although most user interactions are disabled, users can still reconfigure and adjust the window, or close the program. However, users cannot use the asynchronous behavior of the program. This small detail allows you to keep your program self-confidence.

In my first thread synchronization program, there is no use of any traditional thread structure, such as mutual exclusion or semaphore, seems to be worthless. However, I use the most common way to prohibit the control.

Details - implement a cancel button

Sometimes you want to provide a way for your users to cancel the long operation. What you need is some communication methods between your primary lines, and notify the background thread operations no longer need, you can stop. System.Threading Namespace provides a class for this method: AutoreseTevent.

AutoreteTevent is a simple mechanism for communication between threads. An AutoreteEvent object can have one of two states: there is signal and no signal. When you create an AutoReseTevent instance, you can determine its initial state by constructing the parameters of the function. Then sense the thread of the object to communicate with each other by checking the status of the AutoreseTevent object or adjusts its state with the SET or RESET method of the AutoreteTevent object.

To some extent, AutoreteTevent is like a Boolean type, but it provides features make it more suitable for communication between threads. This example is that it has this ability: a thread can be effectively waiting until an AutoreseTEVENT object becomes a signal from a signal-free state. It is achieved by calling Waitone on this object. Any thread calls Waitone to a signal-free AutoreteTelent object, which will be effectively blocked until the object is signal. Use the Boolean variable thread must register this variable in a loop, which is inefficient. Generally, it is not necessary to use RESET to make an AutoreteTevent to have no signal, because when other threads do beware of the object, it is automatically set to no signal.

Now you need a way to test the AutoreteEvent object for your background threads, you will have many tools to achieve thread cancellations. To accomplish this, call the overloaded form with Waitone and point out a zero-order exceeding time, Waitone, which is more than time, will return immediately, regardless of whether the status of the AutoreteTevent object is signal. If the return value is True, this object is signal; otherwise it returns due to time beyond.

We organize the characteristics of the cancellation. If you want to implement a cancel button, it can cancel a long operation in the background thread, follow these steps:

Join the AutoreteEvent Domain Type on your form By incurring a FALSE parameter in the constructor of AutoreteTevent, setting the object's initial state is no signal. Then, the reference domain of the object is then saved on your form, which is to be able to cancel the background operation of the background thread in the entire life cycle of the form. Add a cancel button on your form. In the Click event processor of the cancel button, it has a signal by calling the SET method of the AutoreteTevent object. At the same time, Waitone is cyclically calling Waitone on the AutoreteTevent object in the logic of your background thread to check if the user is canceled. IF (Cancelevent.waitone (0, False)) {// Cancel Operation

}

You must remember to use zero milliseconds, which avoids unnecessary pauses in the background thread operation. If the user cancels the operation, it will be set to have a signal by the main thread autoreteTevent. When Waitone returns True, your background thread gets a warning and stops operation. At the same time, in the background thread, Waitone is called automatically, the event is automatically set. In order to be able to see an example of the cancellation of the long operating form, you can download the CancelableForm.cs file. This code is a complete program, it is

The CorrectMultithReadedMM.cs in Figure 4 is only slightly different.

Note that in CancelableForm.cs also uses a relatively advanced usage control.invoke, where the EnableControls method is designed to call itself if it is called by an error thread. Do this should be done when it uses any GUI objects on the form or attributes. This enables EnableControls to be able to directly securely securely securely in any thread, which is valid in the implementation of the method hidden the complexity of the Invoke call. These can make the application more maintenance. Note that Control.BeginInvoke is used in this example, which is an asynchronous version of Control.Invoke.

You may notice that the cancellation logic depends on the ability of the background thread to call the periodic cancellation check through Waitone. But what if the problem is being discussed? If the background operation is a single call, will it take a long time like DataAdapter.Fill? Sometimes there will be a solution, but it is not always.

If your long operation does not cancel, you can use a pseudo-canceled method to complete your operation, but do not affect your results in your program. This is not a technical cancel operation, which helps an endureless operation to a thread pool, but this is a one in some cases. If you implement similar solutions, you should use your disabled UI elements from your cancel button event handler, not to rely on the bound background thread through the invoke call enable your control. Equally important to design your background operation thread, test it when it returns it, so that it does not affect the results of the currently canceled operation.

This long operation cancel is a relatively advanced method, which is only feasible in some cases. For example, pseudo cancellation of database queries is like this, but an update, deletion, and insertion of a database are a hysteresis operation. There is a permanent operation result or with feedback, like sound and images, it is not easy to use a pseudo cancellation method because the results of the operation are very obvious after the user's cancellation.

More details - Timers

There is a timer that requires a timer in the application to trigger a regular task. For example, if your program displays the current time on the form of the form, you may update time every 5 seconds. The System.Threading namespace includes a Timer multi-threaded timer class.

When you create a timer class, you finger a cycle of a milliseconds for the timer call, and you also pass a delegate to call you every a clock cycle. The callback occurs on the thread in the thread pool. In fact, each clock cycle is really happening is a work entry queues in the thread pool; generally saying that a call will happen immediately, but if the thread pool is busy, this callback may be a time point at a later time. occur. If you consider using multithreading in your program, you may consider using the timer class. However, if your program uses a Windows Form, you don't have to use multiple thread behavior, there is another timer class that is also called Timer in the System.Windows.Forms name space.

System.Windows.Forms.Timer has a clear benefit compared to its multi-threaded companions: because it is not multi-thread, so you will not call you in other threads, and it is more suitable for extracting window messages for the application. Thread. In fact, the implementation of System.Windows.Forms.Timer is a window message for WM_TIMER in the system. This approach does not have to worry about thread synchronization and communication between thread synchronization and thread communication in your system.windows.forms.timer.

For Windows Forms Class programs, as a good trick is to use System.Windows.Forms.Timer classes unless you especially need a thread in the thread pool to call you. Since this requirement is rare, in order to make things simple, use System.Windows.Forms.Timer as a rule, even in other parts of your program use multiple threads.

Prospect

Microsoft recently showed an upcoming GUI API, codenamed "Avalon", in this issue of this issue (see 70) Charles Petzold '' '' article describes its characteristics. In the Avalon framework, the user interface element is not systematically associated with a special thread; as a replacement each user interface element is associated with a separate logic thread context, implemented in the UICONText class. But when you find that the UICONText class contains the Invoke method, and its sisters becominvoke, you will not be surprised, the same purpose as the name on the control class in the form class is to explain the logical role. of.

About the Author

Jason Clark provides training and consulting for Microsoft and Wintelle, and he is an developer of Windows NT and Windows 2000 Server Team. He is a compilation of the Windows 2000 server program programming book. Contact with jason: jclark@wintellect.com

转载请注明原文地址:https://www.9cbs.com/read-29044.html

New Post(0)