Friday, November 22, 2019
Threading Introduction in Visual Basic
Threading Introduction in Visual Basic To understand threading in VB.NET, it helps to understand some of the foundation concepts. First up is that threading is something that happens because the operating system supports it. Microsoft Windows is a pre-emptive multitasking operating system. A part of Windows called the task scheduler parcels out processor time to all the running programs. These small chunks of processor time are called time slices. Programs arent in charge of how much processor time they get, the task scheduler is. Because these time slices are so small, you get the illusion that the computer is doing several things at once. Definition of Thread A thread is a single sequential flow of control. Some qualifiers: A thread is a path of execution through that body of code.Threads share memory so they have to cooperate to produce the correct result.A thread has thread-specific data such as registers, a stack pointer, and a program counter.A process is a single body of code that can have many threads, but it has at least one and it has a single context (address space). This is assembly level stuff, but thats what you get into when you start thinking about threads. Multithreading vs. Multiprocessing Multithreading is not the same as multicore parallel processing, but multithreading and multiprocessing do work together. Most PCs today have processors that have at least two cores, and ordinary home machines sometimes have up to eight cores. Each core is a separate processor, capable of running programs by itself. You get a performance boost when the OS assigns a different process to different cores. Using multiple threads and multiple processors for even greater performance is called thread-level parallelism. A lot of what can be done depends on what the operating system and the processor hardware can do, not always what you can do in your program, and you shouldnt expect to be able to use multiple threads on everything. In fact, you might not find many problems that benefit from multiple threads. So, dont implement multithreading just because its there. You can easily reduce your programs performance if its not a good candidate for multithreading. Just as examples, video codecs may be the worst programs to multithread because the data is inherently serial. Server programs that handle web pages might be among the best because the different clients are inherently independent. Practicing Thread Safety Multithreaded code often requires complex coordination of threads. Subtle and difficult-to-find bugs are common because different threads often have to share the same data so data can be changed by one thread when another isnt expecting it. The general term for this problem is race condition. In other words, the two threads can get into a race to update the same data and the result can be different depending on which thread wins. As a trivial example, suppose youre coding a loop: For I 1 To 10 DoSomethingWithI()Next If the loop counter I unexpectedly misses the number 7 and goes from 6 to 8- but only some of the time- it would have disastrous effects on whatever the loop is doing. Preventing problems like this is called thread safety. If the program needs the result of one operation in a later operation, then it can be impossible to code parallel processes or threads to do it.Ã Basic Multithreading Operations Its time to push this precautionary talk to the background and write some multithreading code. This article uses a Console Application for simplicity right now. If you want to follow along, start Visual Studio with a new Console Application project. The primary namespace used by multithreading is the System.Threading namespace and the Thread class will create, start, and stop new threads. In the example below, notice that TestMultiThreading is a delegate. That is, you have to use the name of a method that the Thread method can call. Imports System.ThreadingModule Module1 Sub Main() Dim theThread _ As New Threading.Thread( AddressOf TestMultiThreading) theThread.Start(5) End Sub Public Sub TestMultiThreading(ByVal X As Long) For loopCounter As Integer 1 To 10 X X * 5 2 Console.WriteLine(X) Next Console.ReadLine() End SubEnd Module In this app, we could have executed the second Sub by simply calling it: TestMultiThreading(5) This would have executed the entire application in serial fashion. The first code example above, however, kicks off the TestMultiThreading subroutine and then continues. A Recursive Algorithm Example Heres a multithreaded application involving calculating permutations of an array using a recursive algorithm. Not all of the code is shown here. The array of characters being permuted is simply 1, 2, 3, 4, and 5. Heres the pertinent part of the code. Sub Main() Dim theThread _ As New Threading.Thread( AddressOf Permute) theThread.Start(5) Permute(5) Console.WriteLine(Finished Main) Console.ReadLine()End SubSub Permute(ByVal K As Long) ... Permutate(K, 1) ...End SubPrivate Sub Permutate( ... ... Console.WriteLine( pno pString) ...End Sub Notice that there are two ways to call the Permute sub (both commented out in the code above). One kicks off a thread and the other calls it directly. If you call it directly, you get: 1 123452 12354... etc119 54312120 54321Finished Main However, if you kick off a thread and Start the Permute sub instead, you get: 1 12345Finished Main2 12354... etc119 54312120 54321 This clearly shows that at least one permutation is generated, then the Main sub moves ahead and finishes, displaying Finished Main, while the rest of the permutations are being generated. Since the display comes from a second sub called by the Permute sub, you know that is part of the new thread as well. This illustrates the concept that a thread is a path of execution as mentioned earlier. Race Condition Example The first part of this article mentioned a race condition. Heres an example that shows it directly: Module Module1 Dim I As Integer 0 Public Sub Main() Dim theFirstThread _ As New Threading.Thread( AddressOf firstNewThread) theFirstThread.Start() Dim theSecondThread _ As New Threading.Thread( AddressOf secondNewThread) theSecondThread.Start() Dim theLoopingThread _ As New Threading.Thread( AddressOf LoopingThread) theLoopingThread.Start() End Sub Sub firstNewThread() Debug.Print( firstNewThread just started!) I I 2 End Sub Sub secondNewThread() Debug.Print( secondNewThread just started!) I I 3 End Sub Sub LoopingThread() Debug.Print( LoopingThread started!) For I 1 To 10 Debug.Print( Current Value of I: I.ToString) Next End SubEnd Module The Immediate window showed this result in one trial. Other trials were different. Thats the essence of a race condition. LoopingThread started!Current Value of I: 1secondNewThread just started!Current Value of I: 2firstNewThread just started!Current Value of I: 6Current Value of I: 9Current Value of I: 10
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.