Visual Basic Q&A

As a software engineer, I focus on .NET, especially asp.net, C#, WCF and so on, and I am also very interested in Search Engine Optimization.

Entries Tagged ‘thread’

PRB: Cannot Administer Analysis Services by Using DSO in ASP.NET

Symptoms
When you try to use Microsoft Decision Support Objects (DSO) from an ASP.NET application to perform administrative tasks on a server that is running Analysis Services, you may receive an error similar to the following:
When connecting to the local computer that is running Analysis Services:

Cannot connect to the Analysis server on computer ‘MyServer’. Connection to the server is lost
When connecting to a remote computer that is running Analysis Services:

Cannot open connection to Analysis server ‘MyRemoteServer’. Error in data [Possible data corruption]
Resolution
This behavior occurs for two separate reasons. One part of the issue involves the start permissions of the DSO ActiveX DLL. By default, the ActiveX DLLs are carried out in the ASP.NET worker process (Aspnet_wp.exe) under the ASPNET account, when called from an ASPX page.
The other part of the issue is, Aspnet_wp.exe uses a Multi-Threaded Apartment (MTA) model, while DSO uses a Single-Threaded Apartment (STA) model. With the ASP.NET application, the impersonation token is on one of the applications MTA threads and the STA COM component is accessed by a different thread (the single thread in its STA). Because the MTA threads impersonation token is not passed to the STA thread, the STA thread carries out under the security token associated with the Aspnet_wp.exe process.

INFO: Avoid Global Variables in Visual Basic COM+ Components

Symptoms
When you use global variables in Visual Basic 6.0 COM+ Apartment components, data may become corrupted. Visual Basic COM+ components use single-threaded apartment (STA) threads. This may cause data to become corrupted under load because of the mechanism that COM+ uses to bind activities to its pooled STA threads. Microsoft does not recommend the use of global variables in Visual Basic COM+ components.
Resolution
Global variables in Visual Basic are slightly different in scope from global variables in a C++ program. Instead of having one copy of a global variable that all instances of a class share, Visual Basic stores a unique copy of each global variable per thread in thread local storage (TLS). If two instances of the same Apartment class are bound to different STA threads, each STA (and, therefore, each of the two instances of that class) has its own copy of the global variable. Changes that one instance (one STA) makes to the value are notseen by the other instance (a different STA) because each TLS is unique to an STA.
When you configure a Visual Basic Apartment component in COM+, the COM+ activity model may cause a global variable to become corrupted. COM+ binds up to five activities to one of its pooled STA threads, depending on the load. Therefore, five different logical chains of execution, or five callers, can all be bound to one STA thread.
More than onethread cannot run in the same STA at the same time. When a COM method makes a call to an object that is bound to an STA, this call is packaged as a WM_USER message that is posted to the hidden window of that STA. When an outgoing apartment method call, or a cross-process remote procedure call (RPC) is made, the COM channel creates a separate thread to make the actual method call, and then enters the message loop and services the next message in the queue.
Because the STA guards data against concurrency but not against reentrancy, a second caller (activity) on that thread uses the CPU and can gain access to the global TLS data while the first caller is still in progress. This second caller has access to the same data in TLS that the preempted first call may have changed. If the data is changed while the second message is being processed, the data reflects this change immediately. When the first call returns, it finds that the data is different from what appeared previously and determines that the data has been corrupted.
For example, configure a Visual Basic Apartment component that has a class named MyVBClass in COM+. MyVBClass contains code to change the global integer variable g_MyVal. The first caller, client X, creates an instance of MyVBClass, and then calls a method to set g_MyVal to 5. In the same method, MyVBClass performs either a cross-apartment or cross-process RPC call to another COM+ component. The COM channel creates an additional thread to make the actual RPC call, and then enters the COM message pump and handles a pending call from client Y.
Client Y sets g_MyVal to 10, completes its work, and then returns. When the call of client Y is completed, the outgoing method call of client X uses the processor again. Client X’s call reads g_MyVal and expects the value that it set previously (5). However, the value 10 is received. To client X, this is a corrupted value.
In any multithreaded execution environment, Visual Basic globals are unique in the TLS of each thread. However, you have little control over which STA your instances are bound to, unless you explicitly configure your component to use COM+ concurrency. However, COM+ concurrency only guarantees that all instances in the same logical thread of execution are bound to the same STA. When you start a different thread of execution, or when you do not use COM+ synchronization, your instances may not be bound to an STA where the correct global representation is stored. This is another way that you can experience problems when you use globals in Visual Basic.
Microsoft recommends that you do not use global variables in Visual Basic components that run in any multithreaded environment such as IIS and COM+. Instead, you can declare private variables in the class, and then expose them by using public properties as shown in the following sample code.Avoid Global Variable Workaround

‘ Private variable for storing the valuePrivate intMyVal As Integer’ Public property to retrieve the valuePublic Property Get MyValue() As IntegerMyValue = intMyValEnd Property’ Public property to assign the valuePublic Property Set MyValue(myVal As Integer)intMyVal = myValEnd PropertyEmulateMTSBehavior WorkaroundAnother way towork around this problem is to set the EmulateMTSBehavior registry key. This setting causes an instance of an object to be created on its own thread. Therefore, you no longer experience the problem of having two instances that share the same TLS data.

Note After you reach the 100 threads with the EmulateMTSBehavior registry key, the behavior returns to the default setting and you can reuse the threads.
Important Depending on your architecture, setting this registry key may adversely affect the performance of your COM+ application. If you decide to set this registry key, thoroughly stress test your application to verify that the performance is acceptable. For additional information, click the following article number to view the article in the Microsoft Knowledge Base:
303071?(http://support.microsoft.com/kb/303071/EN-US/) INFO: Registry Key for Tuning COM+ Thread and ActivityFor more information about how to set the EmulateMTSBehavior registry key, visit the following Microsoft Web site:
http://msdn2.microsoft.com/en-us/library/ms809941.aspx(http://msdn2.microsoft.com/en-us/library/ms809941.aspx)Intrinsic Visual Basic ObjectsIn Visual Basic code, theApp, the Err, and the Printer intrinsic Visual Basic objects are stored on a per-thread basis in TLS. These objects can also experience the problems that concurrent access to TLS can cause. Use these objects very carefully in a multithreaded distributed environment such as COM+ or Microsoft Internet Information Services (IIS).App Object The App object contains read-only information about the Visual Basic application, and also about methods to log events. By using the App.StartLogging method, a developer can change the properties of the App object to control how events are logged using the App.LogEvent method. When you call App.StartLogging to change the way that events are logged, you affect the global App object that is shared for each of your components on that thread. If your application uses the App.StartLogging method, make sure that you call this to set the correct logMode before each call to App.LogEvent.Printer ObjectWhen you set the properties of the global Printer object, all instances of your Visual Basic component on that thread use the new, updated data. If your Visual Basic components change the Printer properties, you must verify that the properties are set correctly immediately before you print. You must verify the Printer properties because another instance of your component on the same thread may have changed the properties between the time that they were set and the time that the document was spooled off to the printer.Err ObjectVisual Basic uses the Err object to store error information when a runtime error is raised in your Visual Basic component. Because the Err object is stored in TLS, each of your components that are on the same thread share the same copy of that Err object.
Verify that you have completed using the Err object before you make any blocking calls that may permit another Visual Basic component on the same thread to run. Do not make any other out-of-process calls, do not raise events, and do not call DoEvents from within your error handling routine until you have completed using the existing data in the Err object or you may obtain incorrect results.
Never pass the Err object outside your Visual Basic component. The Err object is also a private Visual Basic object. Do not pass it outside the component. Whena second object gains access to the Err object, the Err object calls back to the original Visual Basic component on a different STA to use the data. That data may be incorrect for the current object. If you must pass error information outside your component, pass specific data such as the Err.Number and the Err.Description. For more information, visit the following Microsoft Web site:
http://msdn2.microsoft.com/en-us/library/aa716186(VS.60).aspx(http://msdn2.microsoft.com/en-us/library/aa716186(VS.60).aspx)

Description of race conditions and deadlocks

Symptoms
Visual Basic .NET or Visual Basic 2005 offers the ability to use threads in Visual Basic applications for the first time. Threads introduce debugging issues such asrace conditions and deadlocks. This article explores these two issues.
Resolution
Race ConditionsA race condition occurs when two threads access a shared variable at the same time. The first thread reads the variable, and the second thread reads the same value from the variable. Then the first thread and second thread perform their operations on the value, and they race to see which thread can write the value last to the shared variable. The value of the thread that writes its value last is preserved, because the thread is writing over the value that the previous thread wrote.Details and ExampleEach thread is allocated a predefined period of time to execute on a processor. When the time that is allocated for the thread expires, the thread’s context is saved until its next turn on the processor, and the processor begins the execution of the next thread.
How can a one-line command cause a race condition? Examine the following example to see how a race condition occurs. There are two threads, and both are updating a shared variable called total (which is represented as dword ptr ds:[031B49DCh] in the assembly code).
Visual Basic code:

‘Thread 1Total = Total + val1

‘Thread 2Total = Total – val2 Assembly code (with line numbers) from the compilation of the preceding Visual Basic code:

‘Thread 1 1.moveax,dword ptr ds:[031B49DCh]2.addeax,edi3.jno000000334.xorecx,ecx5.call7611097F6.movdword ptr ds:[031B49DCh],eax

‘Thread 2 1.moveax,dword ptr ds:[031B49DCh]2.subeax,edi3.jno000000334.xorecx,ecx5.call76110BE76.movdword ptr ds:[031B49DCh],eax By looking at the assembly code, you can see how many operations the processor is performing at the lower level to execute a simple addition calculation. A thread may be able to execute all or part of its assembly code during its time on the processor. Now look at how a race condition occurs from this code.
Total is 100, val1 is 50, and val2 is 15. Thread 1 gets an opportunity to execute but only completes steps 1 through 3. This means that Thread 1 read the variable and completed the addition. Thread 1 is now just waiting to write out its new value of 150. After Thread 1 is stopped, Thread 2 gets to execute completely. This means that it has written the value that it calculated (85) out to the variable Total. Finally, Thread 1 regains control and finishes execution. It writes out its value (150). Therefore, when Thread 1 is finished, the value of Total is now 150 instead of 85.
You can see how this might be a major problem. If this were a banking program, the customer would have money in their account that should not be present.
This error is random, because it is possible for Thread 1 to complete its execution before its time on the processor expires, and then Thread 2 canbegin its execution. If these events occur, the problem does not occur.Thread execution is nondeterministic, therefore you cannot control the time or order of execution. Also note that the threads may execute differently in runtime versus debug mode. Also, you can see that if youexecute each thread in series, the error does not occur. This randomness makes these errors much harder to track down and debug.
To prevent the race conditions from occurring, you can lock shared variables, so that only one thread at a time has access to the shared variable. Do this sparingly, because if a variable is locked in Thread 1 and Thread 2 also needs the variable, Thread 2’s execution stops while Thread 2 waits for Thread 1 to release the variable. (For more information, see “SyncLock” in the “References” section of this article.)SymptomsThe most common symptom of a race condition is unpredictable values of variables that are shared between multiple threads. This results from the unpredictability of the order in which the threads execute. Sometime one thread wins, and sometime the other thread wins. At other times, execution works correctly. Also, if each thread is executed separately, the variable value behaves correctly.
DeadlocksA deadlock occurs when two threads each lock a different variable at the same time and then try to lock the variable that the other thread already locked. As a result, each thread stops executing and waits for the other thread to release the variable. Because each thread is holding the variable that the other thread wants, nothing occurs, and the threads remain deadlocked.Details and ExampleThe following code has two objects, LeftVal and RightVal:

‘Thread 1SyncLock LeftVal SyncLock RightVal’Perform operations on LeftVal and RightVal that require read and write. End SyncLockEnd SyncLock

‘Thread 2SyncLock RightVal SyncLock LeftVal’Perform operations on RightVal and LeftVal that require read and write. End SyncLockEnd SyncLock A deadlock occurs when Thread 1 is permitted to lock LeftVal. The processor stops Thread 1’s execution and begins the execution of Thread 2. Thread 2 locks RightVal and then tries to lock LeftVal. Because LeftVal is locked, Thread 2 stops and waits for LeftVal to be released. Because Thread 2 is stopped, Thread 1 is permitted to continue executing. Thread 1 tries to lock RightVal but cannot, because Thread 2 has locked it. As a result, Thread 1 starts to wait until RightVal becomes available. Each threadwaits for the other thread, because each thread has locked the variable that the other thread is waiting on, and neither thread is unlocking the variable that it is holding.
A deadlock does not always occur. If Thread 1 executes both locks before the processor stops it, Thread 1 can perform its operations and then unlock the shared variable. After Thread 1 unlocks the variable, Thread 2 can proceed with its execution, as expected.
This error seems obvious when these snippets of code are placed side by side, but in practice, the code may appear in separate modules or areas of your code. This a very hard error to track down because, from this same code, both correct execution and incorrect execution can occur.SymptomsA common symptom of deadlock is that the program or group of threads stops responding. This is also known as a hang. At least two threads are each waiting for a variable that the other thread locked. The threads do not proceed, because neither thread will release its variable until it gets the other variable. The whole program can hang if the program is waiting on one or both of those threads to complete execution.
What Is a Thread?Processes are used to separate the different applications that are executing at a specified time on a single computer. The operating system does not execute processes, but threads do. A thread is a unit of execution. The operating system allocates processor time to a thread for the execution of the thread’s tasks. A single process can contain multiple threads of execution. Each thread maintains its own exception handlers, scheduling priorities, and a set of structures that the operating system uses to save the thread’s context if the thread cannot complete its execution during the time that it was assigned to the processor. The context is held until the next time that the thread receives processor time. The context includes all the information that the thread requires to seamlessly continue its execution. This information includes the thread’s set of processor registers and the call stack inside the address space of the host process.