Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#

.pdf
Скачиваний:
194
Добавлен:
12.02.2016
Размер:
16.87 Mб
Скачать

Module 14 (Optional): Threading and Asynchronous Programming

43

 

 

 

The Static Method Synchronized Code Region test

The Static Method Synchronized Code Region test calls the

CounterSynchronizedCodeRegion class’s static method, IncrementStatic, that has the [MethodImplAttribute(MethodImplOptions.Synchronized)] attribute. Because synchronized code regions can be used to synchronize static methods, the following correct result occurs:

Starting Static Method Synchronized Code Region Test Start Thread:40 Resource writing count, static:0 Stop Thread:40 Resource writing count, static:1 Start Thread:41 Resource writing count, static:1 Stop Thread:41 Resource writing count, static:2 Start Thread:42 Resource writing count, static:2 Stop Thread:42 Resource writing count, static:3

All Static Method Synchronized Code Region threads have! completed.

The Instance Method Synchronized Code Region test

The Instance Method Synchronized Code Region test calls the

CounterSynchronizedCodeRegion class’s instance method, IncrementInstance, that has the [MethodImplAttribute(MethodImplOptions.Synchronized)] attribute. Because synchronized code regions can be used to synchronize instance methods, the following correct result occurs:

Starting Instance Method Synchronized Code

Region

Test

Start Object:47 Thread:44

Resource writing count,

instance:0

Stop Object:47 Thread:44

Resource writing count,

instance:1

Start Object:47 Thread:45

Resource writing count,

instance:1

Stop Object:47 Thread:45

Resource writing count,

instance:2

Start Object:47 Thread:46

Resource writing count,

instance:2

Stop Object:47 Thread:46

Resource writing count,

instance:3

All Static Method Synchronized Code Region threads

have!

completed.

 

 

 

44

Module 14 (Optional): Threading and Asynchronous Programming

Manual Synchronization

Topic Objective

To describe the use of the Interlocked class methods, the Mutex class, and the

ReaderWriterLock class in manual synchronization.

Lead-in

Let’s look at some options that the .NET Framework provides to create synchronization mechanisms.

!Interlocked methods – synchronize access to a variable that is shared by multiple threads

#CompareExchange, Decrement, Exchange, Increment

#Threads of different processes can use this mechanism to safely handle variables in

shared memory

!Mutex – synchronization between threads across processes

!ReaderWriterLock – single-writer/multiple-reader

*****************************ILLEGAL FOR NON-TRAINER USE******************************

The .NET Framework provides several synchronization classes, which you can use to create your own synchronization mechanisms. Manual synchronization may be useful for the following operations:

!Synchronizing access to a variable that is shared by multiple threads

!Synchronizing between threads and across processes

!Defining a lock that implements single-writer/multiple-reader semantics

Using methods of the Interlocked class

The Interlocked class methods Increment, Decrement, Exchange, and

CompareExchange provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

On modern processors, the methods of the Interlocked class can often be implemented by a single instruction. Thus, the methods of the Interlocked class provide very high-performance synchronization, and can be used to build higher-level synchronization mechanisms, like spin locks.

Module 14 (Optional): Threading and Asynchronous Programming

45

 

 

 

Increment and Decrement

The Increment and Decrement methods combine the operations of incrementing or decrementing the variable and checking the resulting value. This atomic operation is useful in a multitasking operating system, in which the system can interrupt one thread’s execution to grant a slice of processor time to another thread.

Without such synchronization, one thread can increment a variable but be interrupted by the system before it can check the resulting value of the variable. A second thread can then increment the same variable. When the first thread receives its next time slice, it will check the value of the variable, which has now been incremented not once, but twice. The Interlocked variable access methods protect against this kind of error.

Note The C# increment operator (++) and decrement operator (--) are not implemented by atomic operations and therefore do not provide the thread safety that the Increment and Decrement methods do.

Exchange and CompareExchange

The Exchange method atomically exchanges the values of the specified variables. The CompareExchange method combines two operations: comparing the first and third parameter for equality, and if they are equal, storing the second value in the first variable.

The Exchange and CompareExchange methods that are exposed by the Interlocked class take arguments of type Object that can store references. However, type safety requires that all of the arguments be typed strictly as Object; you cannot simply cast an object to Object in the call to one of these methods. Instead, you must create variables of type Object, assign a custom object to that variable, and then pass that variable.

46

Module 14 (Optional): Threading and Asynchronous Programming

The following Visual C# code example only allows a single call to set the property X. The property X is only set once because the CompareExchange method changes the value of _x only when its first and third parameters are equal, that is to say when _x is equal to null. After _x has been set to ovalue, it no longer equals null and the CompareExchange method will no longer modify it.

using System;

using System.Threading;

namespace CompareandExchange

{

class PropertyTest

{

private Object _x; public int X

{

set {

Object ovalue = value; Interlocked.CompareExchange(

ref _x, ovalue, null);

}

get {

return (int) _x;

}

}

}

class Class1

{

static void Main(string[] args)

{

PropertyTest pt = new PropertyTest(); pt.X = 1;

pt.X = 2;

Console.WriteLine("pt.X: {0}", pt.X);

}

}

}

This code outputs:

pt.X: 1

Module 14 (Optional): Threading and Asynchronous Programming

47

 

 

 

Mutex

You can use a Mutex object to synchronize between threads and across processes. The Mutex class provides a synchronization primitive that grants exclusive access to the shared resource to only one thread. If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex. Although Mutex does not have all of the wait and pulse functionality of the Monitor class, it does offer the creation of named mutexes that can be used between processes.

You call WaitOne, WaitAll, or WaitAny to request ownership of the Mutex.

The state of the Mutex is signaled if no thread owns it.

If a thread owns a Mutex, that thread can specify the same Mutex in repeated wait-request calls without blocking its execution. However, it must release the Mutex as many times as it called wait to release ownership. If a thread terminates normally while owning a Mutex, the state of the Mutex is set to signaled and the next waiting thread gets ownership. The Mutex class corresponds to a Win32 CreateMutex call.

ReaderWriterLock

The ReaderWriterLock defines a lock that implements single-writer/multiple- reader semantics. In terms of resources, ReaderWriterLock objects are sufficiently inexpensive enough to be used in large numbers such as with perobject synchronization.

The ReaderWriterLock provides equity between readers and writers. After a writer-lock is requested, no new readers are accepted until the writer has access.

Neither readers nor writers are perpetually denied access. The ReaderWriterLock class supports functionality for upgrading to a writer lock with a return argument that indicates intermediate writes, and for downgrading from a writer lock, which restores the state of the lock. The class recovers from most common failures such as the creation of events. The lock maintains a consistent internal state and remains usable.

48

Module 14 (Optional): Threading and Asynchronous Programming

The following example shows how a class can use a ReaderWriterLock object to allow multiple threads to execute its Read method or a single thread to execute its Write method at any time.

using System;

using System.Threading;

class Resource

{

ReaderWriterLock rwl = new ReaderWriterLock();

public void Read(Int32 threadNum)

{

rwl.AcquireReaderLock(Timeout.Infinite); try

{

// many can do read processing, writers blocked …

}

finally

{

rwl.ReleaseReaderLock();

}

}

public void Write(Int32 threadNum)

{

rwl.AcquireWriterLock(Timeout.Infinite); try

{

// one can write processing, readers blocked …

}

finally

{

rwl.ReleaseWriterLock();

}

}

}

Module 14 (Optional): Threading and Asynchronous Programming

49

 

 

 

Thread Safety and the .Net Framework Classes

Topic Objective

To introduce .NET Framework classes thread safety issues.

Lead-in

Let’s look at the thread safety issues of the .NET Framework classes.

!Public static members of .NET Framework classes are thread-safe – other public members see .NET SDK

!.NET Framework Collections classes, by default, are generally not thread-safe for modification

#Hashtable is thread safe for one writer and multiple readers

!To obtain a thread-safe collection class

#Use or implement a thread-safe wrapper object obtained from a Synchronized method

#Use a locking mechanism

*****************************ILLEGAL FOR NON-TRAINER USE******************************

All public static members (methods, properties, and fields) within the .NET Framework support concurrent access within a multithreaded environment. Therefore, you can invoke any .NET Framework static member simultaneously from two threads without encountering race conditions, deadlocks, or crashes.

To determine whether a .NET Framework class or structure is thread-safe, see the Thread Safety section for that class or structure in the .NET Framework SDK documentation.

If you want to use a nonthread-safe class in a multithreaded environment, you must wrap an instance of the class with code that supplies the necessary synchronization constructs.

50

Module 14 (Optional): Threading and Asynchronous Programming

Collections

By default, Collections classes are generally not thread-safe. Multiple readers can safely read the collection; however, any modification to the collection produces undefined results for all threads that access the collection, including the reader threads.

You can make Collections classes thread safe by using any of the following techniques:

!Create a thread-safe wrapper by using the Synchronized method and access the collection exclusively through that wrapper. When implementing the Synchronized method, derived classes must override the IsReadOnly property to return the correct value.

!If the class does not have a Synchronized method, derive from the class and implement a Synchronized method by using the SyncRoot property.

!Use a locking mechanism, such as the lock statement in Visual C# (SyncLock in Visual Basic), on the SyncRoot property when accessing the collection.

By default, only the Hashtable class guarantees thread safety when one writer and multiple readers simultaneously access the collection. You can make the collection thread-safe for multiple writers by using any of the preceding techniques.

The Array class does not include a Synchronized method and, although it has a SyncRoot property, you cannot derive from the class. Therefore, you can make an array thread safe only through the locking mechanism.

Module 14 (Optional): Threading and Asynchronous Programming

51

 

 

 

" Special Thread Topics

Topic Objective

To provide an overview of the topics that you will cover in this section.

Lead-in

Having looked at threading in general and within the context of the .NET Framework, let’s focus now on some specialized thread topics.

!Timer Class

!Thread Pools

!Threads and COM Interoperability

!Using Threads with Windows Forms Controls

!Best Practices for Working with Threads

*****************************ILLEGAL FOR NON-TRAINER USE******************************

In addition to the basic thread creation and management operations and the thread safety support through synchronization mechanisms, the .NET Framework provides other interesting areas of threading functionality.

In this section, you will learn about timers and thread pools. The

System.Threading namespace includes:

!A Timer class that enables a delegate to be called after a specified amount of time

!A ThreadPool class that manages groups of threads

!An IOCompletionCallback class to enable notification when an I/O operation completes

You will also learn how the runtime synchronizes access to shared resources between unmanaged COM objects and managed objects in a way that ensures thread safety.

In addition, you will learn about the requirements for dealing with nonthreadsafe Windows Forms controls, and how you can optimize the performance effects that are associated with marshaling method calls.

Finally, you will learn the recommended best practices for implementing thread-safe code.

52

Module 14 (Optional): Threading and Asynchronous Programming

Timer Class

Topic Objective

To describe how to use the

Thread.Timer class with a delegate to execute methods periodically.

Lead-in

The Thread.Timer class provides functionality to execute a method at specified intervals.

!Thread.Timer class - periodically executes a method

#Threading.TimerCallback delegate for callback method

#Change method changes timer values

#Dispose method frees the resources held by the timer

Timer timer = new Timer( Timer timer = new Timer(

new TimerCallback(CheckStatus), null, 0, 2000); // … new TimerCallback(CheckStatus), null, 0, 2000);

// …

static void CheckStatus(Object state) { static void CheckStatus(Object state) {

Console.WriteLine("Checking Status.");

}}

Console.WriteLine("Checking Status.");

*****************************ILLEGAL FOR NON-TRAINER USE******************************

The Thread.Timer class provides a mechanism for executing methods at specified intervals. You cannot inherit from this class.

To specify the methods associated with a Timer, use a TimerCallback delegate. Specify the timer delegate when the timer is constructed. The timer delegate cannot be changed. The method calls do not execute in the thread that creates the timer; they execute in a separate thread that is automatically allocated by the system.

When you create a timer, you specify an amount of time to wait before the first invocation of the delegate method (due time), and an amount of time to wait between subsequent invocations (period). A timer invokes its methods when its due time elapses, and invokes its methods once per period thereafter. You can change these values, or you can disable the timer, by using the Change method.

When a timer is no longer needed, use the Dispose method to free the resources held by the timer.

Note There are multiple Timer classes in the .NET Framework. Be careful not to confuse the Thread.Timer class with the System.Timers.Timer and

System.Windows.Forms.Timer classes. For more information about these classes, see the .NET Framework SDK documentation.

Соседние файлы в папке c#