Introduction
Write multithreaded Microsoft? Message Queue (MSMQ) trigger application is always a fearful thing. However, the emergence of .NET framework threads and messages make this work easier than before. These classes allow you to use any language for the .NET framework to write multi-threaded applications. Previously, tools such as Microsoft Visual Basic • were very limited. Therefore, C has to be used to write multi-threaded code, construct a solution consisting of multiple processes or ActiveX DLL through Visual Basic (this solution is not ideal), or simply gives up multithreading. Use the .NET framework, you can build a variety of multi-threaded applications without considering which language is selected.
This article will gradually introduce the process of building a multi-threaded application from the Microsoft message queue. This article will focus on two namespace system.threading and system.Messaging. Sample code is written in C # language, but you can easily convert it to the language you are using.
Thread background
In the Win32 environment, threads have three basic modes: single thread, unit thread, and free thread.
Single thread
Some applications you originally written are probably a single-threaded application, including only threads corresponding to the application process. The process can be defined as an application's instance, with the memory space of the application. Most Windows applications are single-threaded, that is, all work is done with a thread.
Unit thread
The unit thread is a slightly complex thread mode. The code for marking the unit thread can be performed in its own thread and is limited to its own unit. Threads can be defined as entities owned by the process. This process will be scheduled. In unit thread mode, all threads run within the respective subsection ranges in the main application memory. This mode allows multiple code instances to run independently. For example, before .NET, Visual Basic is limited to creating unit thread components and applications.
Free thread
The free thread is the most complex thread mode. In the free thread mode, multiple threads can simultaneously call the same methods and components. Unlike unit threads, the free thread will not be limited to stand-alone memory space. You may need to use free threads when your application must make a large similar and independent mathematical calculation. In this case, you need to generate multiple threads to use the same code example to perform calculations. It may be C developers only write application developers who write free thread applications because languages like Visual Basic 6.0 are almost impossible to write free thread applications.
Use thread mode
In order to make you have a certain concept on thread mode, we can imagine it to move from a house to another. If you use a single-threaded method, you will need to complete all your work from the package to the bag to the package. If you use the unit thread mode, you invite a good friend to help. Every friend works in a separate room and can't help people working in other rooms. They are responsible for their own space and the items in space. If you use a free thread method, you still invite the same friends to help, but all friends can work in any room and package items. Similar to this, your house is a process running all threads. Each friend is a code instance, handling items for the resources and variables of the application.
This example explains the advantages and disadvantages of different thread modes. The unit thread is faster than a single thread because there are multiple component instances at work. In some cases, the free thread is more efficient than the unit thread, because everything happens, and you can share all resources. However, this may have problems when multi-thread changes shared resources. Suppose one starts to use the box to pack kitchen utensils, at this time, another friend came in, to use the same box to package the bathroom. The first friend sticked to "kitchen utensils" on the box, and another friend covers the original label with a "toiletries" tag. As a result, when you are unpacking, the kitchen supplies will be moved to the bathroom. Example application
The first step is to check the design of the sample application. The application will generate multiple threads, and each thread listens for messages from the MSMQ queue. This example uses two classes, main FORM classes, and custom MQListen classes. The FORM class will process the user interface and create, manage, and destroy the auxiliary thread. The MQListen class contains all code, including the message queue factors required for the auxiliary thread run.
Prepare an application
To launch an application, open Visual Studio .NET and create a new C # Windows application called MultithreadedMqlistener. Open the properties of the form, name it queuelistenerform. After drawing the initial form, drag and drop two labels, two buttons, one status bar, and two text boxes to the form. Name the first text box Server, and the second text box named queue. Name the first button StartListening, the second button is named stoplistence. You can keep the default name STATUSBAR1 in the status bar. Next, click the Project menu and click Add Reference to add a reference to System.Messaging Namespace. Find and select System.Messaging.dll in the .NET component list. Namespace contains classes used with MSMQ queue communication. Next, click the File menu, and then click Add New Item to add a new class in the project. Select the Class template and name it Mqlisten. Add the following USING SOSTEM.THREADING; Using System.MESSAGING; System.Threading Name Space Allows you to access all necessary thread features, in this case, you can access the Thread class and ThreadInterruPtexception construct function. This namespace also includes many other advanced features, which are not discussed in detail. System.Messaging Namespace Allows you to access the MSMQ function, including send messages to the queue and receive queue messages. In this case, you will use the MessageQueue class to receive messages. You must also add USING SYSTEM.THREADING in the main form code.
After all reference is in place, you can start writing code.
Auxiliary thread
First, you need to build a MQListen class that encapsulates all threads. Insert the following code into mqlisten.
// c # public class mqlisten {private string m_machinename; private string m_queueename; // Constructor Receive the necessary queue information. Public mqlisten (String Machinename, String Queuename) {m_machinename = Machinename; m_queueename = queuename;} // Each thread is used to listen to a unique way to listen to the MQ message PUBLIC VOID LISTEN () {// Create a MessageQueue object. System.Messaging.MessageQueue MQ = New System.Messaging.MessageQueue (); // Set the path properties of the MessageQueue object. MQ.PATH = M_MACHINENAME "// private $ //" m_queueename; // Create a Message object. System.Messaging.Message Message = new system.Messaging.Message (); // Repeat the above step until the interrupt is received. While (TRUE) {TRY {// Sleep to capture interrupt when the interrupt is issued. System.threading.thread.sleep (100); // Sets the Message object to be equal to the results of the received function. // Duration (days, hours, minutes, seconds). Message = mq.receive (New TimeSpan (0, 0, 0, 1)); // Displays the tag of the received message System.Windows.Forms.MessageBox.show ("Label:" Message.label;} catch ThreadInterruptedExcection E) {// capture ThreadInterrupt from the main thread and exit. Console.writeline ("exiting thread"); message.dispose (); mq.dispose (); break;} catch (exception genericexception) {// Capture all exceptions thrown during the reception process. Console.writeline (genericexception.Message);}}}} code discussion
The MQListen class contains a function different from the constructor. This function encapsulates all the work to be performed. In the main thread, you pass a reference to the thread constructor to execute the function when starting the thread.
The first thing for Listen is to set a message queue object. The MessageQueue constructor is overloaded through three implementations. The first implementation uses two parameters: a string parameter, specifies the location of the listening queue; a Boolean value parameter indicates whether the first application for the access queue gives exclusive read queue permissions. The second implementation only uses the queue path parameters, and the third implementation does not use parameters. For the sake of simplicity, you can use the third implementation to allocate the path in the next row.
If you reference the queue, you must create a message object. There are three messaging functions. If you want to write a message to the queue, you can use the first two implementations. Both implementations use two objects: one is an object in the message body; one is the IMESSAGEFORMATTER object that defines how objects are serially serialized to the message body. In this example, you will read data from the queue to initialize the empty message object.
After initializing the object, you need to enter the main loop of all work. Then, when the main thread calls Interrupt to terminate these threads, only the thread is interrupted in a wait, sleep or connection state. If it is not in the above three states, it will be interrupted until a next time you enter the three states. To ensure that the auxiliary thread goes into wait, sleep or connection, call the Sleep method located in the System.Threading namespace. For C and Visual Basic developers who have used the Windows API sleep function, the SLEEP method is not unfamiliar. It only uses a parameter: threads at the number of sleep states. If you never call the SLEEP, the secondary thread will never enter the status of the interrupt request, and will continue without restriction unless you manually turn off the process. There are two implementations in the MQ Receive method. The first implementation does not use parameters, will wait for the reception message. Second implementation (this example uses this implementation) Use the TimeSpan object to specify a timeout value. The Timespan constructor contains four parameters: days, hours, minutes, and seconds. In this case, the Receive method will wait a second before the timeout and returns.
The received message will be assigned to the previously created message object, and then it can be processed. This example opens a message box with a label and deletes this message. If you want to use this code in actual use, you can place any message processing code here.
When the auxiliary thread receives the Interrupt request, a ThreadInterruptedException is issued. To capture this exception, include the Sleep and Receive functions in the Try-Catch block. You should specify two capture: the first one for capturing an abnormality, the second error exception for processing captured. When you capture an interrupt exception, first write it to the debug window that is exiting. Next, call the DISPOSE method for the queue object and message object to ensure that all memory is empty and sent to the memory recovery. Finally, interrupt the While loop.
After the function exits the While cycle, the associated thread will end immediately, the code is 0. In the debug window, you will see a message, such as "THREAD '
'(0x660) HAS EXITED WITH CODE 0 (0x0) "(thread'
'(0x660) has exited, the code is 0 (0x0)). Now, the thread has exited the environment and has been automatically destroyed. The main thread and auxiliary thread do not need to perform a special clear operation.
Main form
The next step is to add code to the form to generate a secondary thread and launch the MQListen class for each auxiliary thread. First, add the following function to the form:
// C # private void startthreads () {int loopCounter; // thread count stoplisteningflag = false; // track the sign of the secondary thread should // terminate. // Declare a array containing 5 threads as a secondary thread. Thread [] threadArray = New Thread [5]; // The statement contains all the codes of all the code of the auxiliary thread. Mqlisten objmqlisten = newmqlisten (this.ServerName.text); for (loopCounter = 0; loopCounter To start this function, create a thread array containing 5 items. This array will keep the reference to all threads for future use. The constructor of the MQListen class uses two parameters: contains the computer name of the message queue and the name of the queue to be listened. The constructor uses the value in the text box to assign these two parameters. To create a thread, you need to enter the loop to initialize each thread object. The Thread constructor requires you to deliver a delegate that points to the function you want to call when calling the START method of the thread. You want the thread to start using the MQListenTen.listen function, but the thread is not a delegate. In order to meet the requirements of the thread constructor, you must pass a ThreadStart object that will create a delegation of a given function name. At this point, pass a reference to the ThreadStart object to the MQListenTen.listen function. Since the array element has been initialized, please call Start to start the thread. After all threads start, use the appropriate messages to update the status bar in the form. With the running and listening queue of the thread, the main thread will wait for the user to request the application to stop listening. To do this, the main thread will enter a while loop until you click the Stoplistening button to change the value of the stoplisteningflag. In this waiting cycle, the application will allow the application to use the Forms.Application.doEvents method to handle other jobs that need to be processed. This is the same as the old doevents method for readers who are familiar with Visual Basic. For readers who are familiar with C , this is equal to writing a MSG pump. When the user clicks on the stoplistening button, the loop will exit and enter the thread shutdown code. To turn off all threads, the code must check the thread array and send an interrupt signal to each thread. Inside this loop, please call the Interrupt method to each thread in the array. The code in the MQListen class will continue to be performed normally before calling this method. Therefore, you can call each auxiliary thread for Interrupt without having to consider whether the thread is processing other events. After completing, the thread class will process all threads. Finally, update the status bar in the main form before exiting. Now you need to add code after the button. Add the following code to the Click event of the StartListening button: // C # Statusbar1.text = "Starting Threads"; STARTTHREADS (); This will update the status bar and call the StartThreads method. For the StopListence button, you only need to use the code to set the stoplisteningflag to true: // C # Stoplisteningflag = true; The final step is to add a window size variable for StoplisteningFlag. Add it to the top of the form code: // C # PRIVATE BOOL Stoplisteningflag = FALSE; To test an application, you can download MQWRITE, which is a sample application written to the message queue. Multithreaded code problem You have completed the sample code, so you have a tool you need to write your own multi-threaded application. Threads can significantly improve the performance and scalability of certain applications. While functions are enhanced, you must also understand the thread is dangerous. Using threads may undermine your application, so that the situation does exist. Threads may stop running, causing unpredictable consequences, even causing the application to stop running. If you have multiple threads, make sure that there is no interoperability to wait for a certain or complete. If the operation is wrong, it may cause a deadlock state, and both threads cannot be completed because they are waiting. If multi-threaded requires access to resources that cannot be easily shared (such as floppy drives, serial ports, or infrared ports), you may need to avoid using threads or requires a more advanced thread tool such as SyncLocks or Mutexes to manage concurrency. If two threads are trying to access these resources, one of the threads will not be able to obtain resources, or will result in data corruption. Another common problem using thread is a competitive state. If a thread is writing a data into a file, while another thread is reading data from the file, you will not be able to know which thread is complete. This situation is called a competitive state because the two threads are at the end of the file. If the read thread is quickly written, it will return the result that cannot be expected. When using a thread, you should also consider whether all threads can work completely independently. If it is really necessary to pass data, when the data is relatively simple, you can do it well. When passing complex objects, the package-back-round moving package will be very considerable. This will result in additional overhead of operating system management and reduces overall performance. Another problem is to transfer the code to other developers' transfer costs. Although .NET does make threads easier, please note that the next developer who maintains your code must understand the thread to use. Although this is not to avoid using threads, it fully illustrates sufficient code notes. These problems themselves do not disperse your enthusiasm for using threads, but you should take into account these issues when designing applications and deciding whether to use threads. Unfortunately, this article cannot discuss some ways to avoid these issues in detail. If you have decided to use a thread but have some questions above, check SyncLocks or Mutexes to see if you can solve the problem or boot your use of other solutions. to sum up With the above information, you can write applications using threads. However, in the process of writing, keep in mind the questions mentioned above. If you are used, the multi-threaded application will have better performance and scalability than a single thread. However, if you use it properly, use the thread to be counterclockwise, and will cause the application to be unstable.