|
|
BROWSE
All Titles WordPress Web Services SOA BPEL Web Graphics & Video Web Development RAW Portugues, Espanol, Italiano, French PHP/MySQL Oracle Open Source Networking & Telephony Moodle Microsoft & .NET Linux Servers jQuery Joomla! JBoss Java e-Learning e-Commerce Dynamics Drupal CRM Cookbook Content Management Beginner Guides Architecture and Analysis AJAX Future Titles Recently Published Titles Want to know more about Packt's Article Network? Interested in contributing your article ideas? Please visit our FAQ for more information. See More In order to solve problems that arise in concurrently running threads in applications, we need new debugging techniques suitable for the new parallelism environments that occur in Visual C#. In this article by Gastón C. Hillar, we will learn many tricks and debugging procedures that will help us find solutions to multithreaded application problems and have a better understanding of the execution of parallel threads. We will be performing the following exercises:
See More |
Debugging Multithreaded Applications as Singlethreaded in C#
We can identify threads created using both the BackgroundWorker component and the Thread class. We can also identify the main application thread and we learned about the information shown by the Threads window. However, we must debug the encryption process to solve its problem without taking into account the other concurrent threads. How can we successfully debug the encryption engine focusing on one thread and leaving the others untouched? We can use the Threads window to control the execution of the concurrent thread at runtime without having to make changes to the code. This will affect the performance results, but it will allow us to focus on a specific part of the code as if we were working in a single-threaded application. This technique is suitable for solving problems related to a specific part of the code that runs in a thread. However, when there are problems generated by concurrency we must use other debugging tricks that we will be learning shortly. The Threads window does a great job in offering good runtime information about the running threads while offering a simple way to watch, pause, and resume multiple threads. Time for action – Leaving a thread running aloneYou must run the encryption procedure called by ThreadEncryptProcedure. But you want to focus on just one thread, in order to solve the problem that the FBI agents detected. Changing the code is not an option, because it will take more time than expected, and you might introduce new bugs to the encryption engine. Thus, let's freeze the threads we are not interested in! Now, we are going to leave one encryption thread running alone to focus on its code without the other threads disturbing our debugging procedure:
What just happened?It is easy to debug a multi hreaded application focusing on one thread instead of trying to do it with all the threads running at the same time. We could transform a complex multi threaded application into a single-threaded application without making changes to the code. We did it at runtime using the multithreading debugging features offered by the C# IDE. We suspended the execution of the concurrent threads that would disturb our step-by-step execution. Thus, we could focus on the code being executed by just one encryption thread. Freezing and thawing threadsFreezing a thread suspends its execution. However, in the debugging process, we would need to resume the thread execution. It can be done at any point of ti me by right-clicking on a suspended thread and selecting Thaw in the context menu that appears, as shown in the following image:
By Freezing and Thawing threads (suspending and resuming), we can have an exhaustive control over the threads running during the debugging process. It helps a lot when we have to solve bugs related to concurrency as we can easily analyze many contexts without making changes to the code—which could generate new bugs. Nevertheless, when developing multithreaded applications, we must always test the execution with many concurrent threads running to make sure it does not have concurrency bugs. The debugging techniques allow us to isolate the code for evaluation purposes, but the final tests must use the full multithreading potential. Viewing the call stack for each running threadEach thread has its own independent stack. Using the Call Stack window, we can move through the methods that were called, as we are used to doing so in single-threaded applications. The main difference in doing this with multithreaded applications is that when the active thread changes, the Call Stack window will also show different content. Debugging a multi hreaded application using the techniques we are learning is an excellent way to understand how the different threads run and will improve our parallel programming skills. To show the call stack for the active thread, press Ctrl + Alt + C or go to Debug | Windows | Call Stack in the main menu. Make sure the Threads window is also visible to take into account the active thread when analyzing the call stack, as shown in the following image:
Have a go hero – Debugging and enhancing the encryption algorithmUsing the multithreaded debugging techniques we have learned so far, develop a new version of this application with the encryption problem solved. Take into account everything we have studied about freezing and thawing threads. Check the randomly generated garbage and the way it is applied to the generated encrypted string. Making some changes to it, you can have a robust encryption process that differentiates each output with the same input text. You can improve the new versions by using new randomly generated garbage to enhance the encryption algorithms. Oh no! You have to explain to the agents the changes you made to the encryption procedure, and how it works. C# 2008 and 2005 Threaded Programming: Beginner's Guide
Showing partial results in multithreaded codeWe have learned new debugging features provided by Visual C# that help us a lot in troubleshooting bugs in multithreaded applications without dying in action–transforming it into a single-threaded application without making changes in its code. However, sometimes, we must show partial results of a procedure to help us understand what is happening while it is running. How can we safely show partial results in procedures being executed in many concurrent threads? We cannot show the partial results in the UI controls. We can do that using many BackgroundWorker components, but it would require lots of changes to the code and add a great complexity to the application. We do want to take a simpler approach. Fortunately, the IDE offers us the Immediate Window, and it can help us in our task. Time for action – Explaining the encryption procedureThe FBI agents want you to explain to them the encryption procedure, showing them partial results. Using the debugging techniques learned so far, you isolate an encryption thread and begin executing it step-by-step, inspecting variables to show the values. Nevertheless, they do not understand it this way. They want you to copy and paste the partial results in a document and then explain to them using what just happened. Don't worry; using the Immediate Window, it is very easy! Now, we are going to add code to the Encrypt procedure to show partial results in the Immediate Window as the text is being encoded:
What just happened?The results shown in the Immediate Window are a great mess. How can you explain that to the FBI agents? The answer would be to isolate an encryption thread and show the results for just that one thread using the debugging techniques learned. Then, you can copy the contents of the Immediate Window to a word processor! The outputs shown in the Immediate Window are the results of the code executed in many concurrent threads. Therefore, it is very difficult to understand the real encryption execution sequence. One possible solution is isolating one thread and running just that one. We have already learned how to do so. The other is to show the information only when it is running on a certain thread. We can check it in the procedure executed by the thread using Thread.CurrentThread and comparing the name. As we can see, Thread.CurrentThread is very useful in defining conditional execution of certain code according to some information provided by the thread context in which the methods are being run. Besides, it is very useful while debugging. Showing thread-safe outputThe System.Diagnostics.Debug.Print method allows us to show information at runtime from many threads in a thread-safe way. Using it, the application can provide us with very important feedback to understand what happens when multiple concurrent threads are running at the same time. Running a multithreaded application step-by-step, even without isolation, does not represent the real concurrent execution that happens at runtime without breakpoints. Therefore, it is very important to have some feedback to test certain conditions using the System.Diagnostics.Debug.Print method. However, we must remember that the application's performance will degrade when using the System.Diagnostics.Debug.Print method. Thus, the performance must be measured without calls to this method or any interfering debugging techniques. Using this method, combined with all the debugging techniques known for single-threaded applications, such as inspecting values, setting breakpoints, and tracepoints, we will not have any trouble in solving bugs in multithreaded code. Time for action – Isolating resultsUsing the debugging techniques learned to isolate a single thread, you can show the results of one encryption thread in the Immediate Window. This way, you will be able to explain to the FBI agents what just happened in the encryption procedure. Furthermore, finally, they will be happy with you! Now, we are going to isolate the thread as we did in a previous example, but using our recently added code to the Encrypt procedure to show partial results in the Immediate Window as the text is being encoded:
What just happenedYou explain the encryption procedure to the FBI agents, step-by-step with the example you obtained in the Immediate Window. They are amazed with the simplicity of your examples and your parallel processing skills! They think you are ready to cooperate with a very interesting project in NASA. But, before that, there is a new mission for you. As we isolated one encryption thread, the text shown in the Immediate Window is the result of the linear execution of just one thread. Isolation is a great resource for debugging multithreaded applications. Using it, we can easily find and solve bugs. Understanding thread information in tracepointsWhen debugging multithreaded applications, the information shown by the tracepoints is usually useful. They can be used in a manner similar to their usage when debugging singlethreaded applications. But they show us information about the running thread. In order to solve bugs, sometimes we need to know whether a method was executed or not. In a multithreaded applicati on, this can be more confusing, especially when we are writing our first parallelized structures. To create a tracepoint, you must right-click the line of code and select Breakpoints | Insert Tracepoint in the context menu that appears. The When Breakpoint Is Hit dialog box will be shown, asking for the parameters for the behavior of the tracepoint, as shown in the following image:
When debugging multithreaded applicati ons, the $TID and $TNAME keywords are very important because they will give us information in the Immediate Window with the thread ID and its name, as shown in the following line: Function: SMSEncryption.frmSMSEncryptionEngine.ThreadEncryptProcedure(object), Thread: 0x7FC Encryption #0 When you need to know the methods the concurrent threads are running, using tracepoints is a very good choice, because you do not need to change the code to show results in the Immediate Window. Have a go hero – Concurrent decryptionAs mentioned earlier, there is still some work left to be done. The FBI wants to test the time needed to break the encryption. Remember, they have a computer with 16 quad-core microprocessors (64 cores). They do not want you to break the code, but they ask you to create a new application that decrypts each encrypted code. That is, you must decrypt the code simultaneously as the other threads are encrypting the original code. You have to use a queue scheme. The encryption threads add encrypted code to that queue, while the decryption threads remove code from it. Using everything that we know and the debugging techniquesstudied in this article, develop a new version of an application that shows the incoming and outgoing SMS messages with their information in a grid. Use half of the processing power to encrypt and the other half to decrypt concurrently. The text to be decrypted must be entered or copied by the user. Therefore, the user interface must show the progress but must be responsive to the user. While many threads are encrypting text, the user can copy the results and paste them in the decrypti on input TextBox. The encryption and decryption processes must be launched by different buttons. Enhance the new application detecting the activity of the concurrent threads. If there is no decryption process, the encryption engine must work with as many threads as cores available, and vice versa. It must work in a dynamic way to achieve the best possible performance at any time. Do not be disappointed! You can do it! SummaryIn this article, we saw how to freeze many threads to allow us to debug one thread at a time, without the problems related to concurrency while executing the application step-by-step. We inserted breakpoints and tracepoints to simplify troubleshooting complex multithreaded applications. We also generated partial results information without creating problems for the multithreaded code.C# 2008 and 2005 Threaded Programming: Beginner's Guide
About the AuthorGastón C. Hillar has been working with computers since he was eight. He began programming with the legendary Texas TI-99/4A and Commodore 64 home computers in the early 80’s. He has a Bachelor degree in Computer Science, graduated with honors and an MBA (Master in Business Administration), graduated with an outstanding thesis. He worked as developer, architect, and project manager for many companies in Buenos Aires, Argentina. Now, he is an independent IT consultant and a freelance author always looking for new adventures around the world. He also works with electronics (he is an electronics technician). He is always researching about new technologies and writing about them. He owns an IT and electronics laboratory with many servers, monitors and measuring instruments. He is the author of more than 40 books in Spanish about computer science, modern hardware, programming, systems development, software architecture, business applications, balanced scorecard applications, IT project management, Internet and electronics. He usually writes articles for Spanish magazines “Mundo Linux”, “Solo Programadores” and “Resistor”. Books from Packt |
TOP TITLES ![]()
In order to simplify parallelism complexities and to avoid many concurrency pains, we must use the object-oriented capabilities offered by the C# programming language and design patterns. In this article, we will drastically simplify the creation of new parallelized code avoiding some advanced concurrent programming difficulties. Reading this article by Gastón C. Hillar and following the exercises we shall :
See More |
| ||||||||