Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml

AspAutocadCDot netExcelFox proHtmlJava
LinuxMathcadPhotoshopPhpSqlVisual studioWindowsXml

Multiple Threads in Applications - STA Threading Model

c



+ Font mai mare | - Font mai mic



Multiple Threads in Applications

If you programmed in versions of VB prior to .NET, you might know that VB supported multiple threads within a COM container, such as MTS or COM+. Well, although multiple threads were supported by VB5/6, the threading model they supported was Single Threaded Apartments (STA). If you come from Visual C++ then you'd have options to build both MTA (Multi Threaded Apartments) and STA applications. However, the .NET Framework does not retain the concept of Apartments and it manages all of the threads within AppDomains. By default, all .NET applications are multithreaded and any code can access any object at any time. Thus, we have to be very careful with static resources in the managed code.



The .NET Framework supports both managed and unmanaged threads and all the Win32 threading models such as STA and MTA. When you are trying to access COM components from managed code, unmanaged threads are created by the legacy COM components. Threads in the .NET Framework are created using the Thread object, whether managed or unmanaged.

If you have ever programmed multithreaded programs using the Win32 APIs, you may remember that Win32 supported user-interface threads and worker threads. As you learned in Chapter 1, the threading names have now changed into Apartment Model Threading and Free Threading respectively. The .NET Framework supports two basic threading models, which are Apartment Model Threaded or Single Threaded Apartment (STA) components, and Free Threaded or Multi Threaded Apartment (MTA) components. When we create a thread in .NET, by default it is an MTA thread.

You should only use the STA threading model when you're going to access STA-based COM components such as VB6 COM components. Otherwise, you shouldn't mark the current thread as STA, since it involves a significant performance hit to the application.

To reiterate what you learned earlier, an apartment is the logical container within the AppDomain for sharing threads in the same context. Objects reside inside an AppDomain and the context is created when an object is created during the activation process.

STA Threading Model

An STA thread apartment works using a concept called Object-per-Client model, meaning the code that creates the STA thread apartment owns its threads. There will only be one thread in any apartment as shown in Figure 1.


Figure 1

In STA threading, all the calls to a thread will be placed in a queue and the calls will be processed one by one. Therefore, the STA thread will never execute multiple methods simultaneously. STA threads have their own private data and they don't share data between threads. This makes the threading model safe and avoids any data corruption and synchronization problems. However, this does restrict the options available to the developer, and performance suffers, as data has to be copied with every thread created.

As you can see from the diagram, AppDomain X has two STA threads, X and Y, running inside, and each of the STA Apartments has only one thread. The term Thread Affinity is used when defining the relationship between the thread and the code that creates the thread. When a call is made to an STA apartment thread, then calls between the caller and the thread are handled by the contexts in the AppDomain, and the contexts maintain the thread affinity.

If your managed application is going to use unmanaged legacy COM components, then it is very important to know the threading model of the COM components before accessing them. If you don't mark the correct threading mode in your application, there could be some unexpected bugs and catastrophic errors in your application. The threading model information can be found in the registry under the HKEY_CLASSES_ROOTCLSID InProcServer32 key.

If you want to specify that you are using the Apartment Threading model, then apply the STAThreadAttribute attribute on the Main method.

[STAThreadAttribute]
static void Main()


This attribute should only be used if we're trying to access legacy STA components from the managed code. Otherwise, mark the Main method as MTAThreadAttribute:

[MTAThreadAttribute]
static void Main()

The same principal applies for ASP.NET applications. If your ASP.NET page is accessing an STA COM component, then you have to use the ASPCompat directive at the top of the ASP.NET page:

<%@ Page AspCompat='true' %>

By default, all the ASP.NET pages are multithreaded and when we use the AspCompat directive, the ASP.NET page is marked as STA. This will ensure the ASP.NET page is compatible with the threading model of a COM component.

When you mark the ASP.NET page to run under the STA threading model, the performance of the application may suffer.

Note 

If you are using VB.NET then you can use CreateObject statement to instantiate COM objects. Since C# doesn't allow late binding, the only way to call COM objects in late binding mode is to use reflection.

MTA Threading Model

The biggest difference between an STA and an MTA threaded apartment is that an MTA apartment can have more than one thread running simultaneously in the same apartment using all the shared data available in the apartment. This is illustrated in Figure 2.


Figure 2

Since the MTA model supports simultaneous multiple thread execution, it becomes the caller's responsibility to synchronize the global data between multiple threads. Many of these issues were covered in the previous chapter.

Specifying the Threading Model

The threading model for a thread can be set using the ApartmentState property of the Thread class. The ApartmentState enumeration defines the types of threading models supported by .NET.

Enumeration Value

Meaning

MTA

Creates a multi-threaded apartment

STA

Creates a single-threaded apartment

Unknown

The apartment property of the Thread class is not set

As we've already learned, you should only mark the thread as STA thread if you are going to access an STA-threaded legacy COM component. Otherwise, your threading model is in the default MTA threading model.

Designing Threaded Applications

A multithreaded program has two or more threads (flows of control) and can achieve significant performance gains with concurrency, with or without parallel thread execution. Concurrent thread execution means that two or more threads are executing at the same time. Parallelism occurs when two or more threads execute simultaneously across two or more processors.

In this section, we'll talk about real threading considerations and issues. Before you start developing applications, you should ask yourself these questions:

Is it possible to subdivide the application to run on different threads?

If it is possible to subdivide, how do I subdivide and what are the criteria for subdividing?

What would be the relationship between the main thread and the worker threads? This defines how the tasks in the application will relate to each other.

You can determine the answer to the first question by inspecting the application. For example, does your application require heavy I/O operations, such as reading an XML file or querying a database, or perform a lot of CPU-intensive processing, such as encrypting and decrypting data, or hashing? If so, these operations could block your application's main thread.

If you've identified that parts of your application are potential candidates for separate threads, then you should ask yourself the following questions:

Does each of the tasks identified use separate global resources?

For example, if you've identified two potential threads for your application and they are both going to use the same global resource, such as a global variable or a DataSet object, then if both threads try to access the global resource at the same time, you could get inconsistent or corrupt data, as shown in the previous chapter. The only way to prevent this kind of problem is by using locks on the global resources, which could leave the other thread waiting. If both of the tasks are going to use the same global resource then it is not a good idea to break the task into two. For some resources, you could use the Monitor class to prevent the threads from locking up. Again, this was shown in Chapter 3.

Over how long a period may the thread need to be blocked?

It is not always possible to build applications that use independent global resources. For example, let's say two tasks in your application rely on a single global DataSet object. If the first task takes a long time to fill the DataSet object (let's say it fills about 50,000 rows from the database), then you would typically lock the DataSet object to prevent concurrency problems. Here a pseudo-code version of the first task:

1. Open the Database connection

2. Lock the global DataSet object

3. Perform the query

4. Fill the DataSet with 50,000 rows from the database

5. Unlock the DataSet object

In this case, the second task needs to wait for a long time before it can access the DataSet object, which happens only when the first task finishes its execution and releases the lock. This is a potential problem and it will likely remove the concurrency of your application. There is a better way to address this problem:

1. Open the Database connection

2. Perform the query

3. Fill the local DataSet with 50,000 rows from the database

4. Lock the global DataSet object

5. Set the local database to global dataset (DSGlobal = DSLocal)

6. Unlock the global DataSet object

In this way, we're not locking the global DataSet object until we need to update it and so we're reducing the time the lock on the global object is held.

Does the execution of one task depend on the other task?

For example, the tasks that you've identified could be querying the database and displaying the data in a DataGrid control. You can split the task into two by querying the database as the first task, and displaying the result in the DataGrid as the second task. The second task does not want to start until the first task has complete. Therefore, separating the querying and displaying the data in a DataGrid into two separate concurrently running tasks is not a viable option. One way around this is to have the first task raise an event when completed, and fire a new thread when this happens. Alternatively, you could use a timer that checks to see if is completed through a public field, and continues the execution of the thread when it has.

Threads and Relationships

The threads spun from a multithreaded application may or may not be related to each other. For example, in every application there will be a main thread that spins other threads and so the main thread becomes the controller of all other threads in the application. There are few common methods that can be used to define the relationship between the threads in a multithreaded application:

Main and Worker thread model

Peer thread model

Pipeline thread model

We will detail each of these models, including some code so that you can see how they might be implemented in your applications.



Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 974
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved