Tải bản đầy đủ - 0 (trang)
4-1. Execute a Method Using the Thread Pool

4-1. Execute a Method Using the Thread Pool

Tải bản đầy đủ - 0trang

CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



using System;

using System.Threading;

namespace Apress.VisualCSharpRecipes.Chapter04

{

class Recipe04_01

{

// A private class used to pass data to the DisplayMessage method when it is

// executed using the thread pool.

private class MessageInfo

{

private int iterations;

private string message;

// A constructor that takes configuration settings for the thread.

public MessageInfo(int iterations, string message)

{

this.iterations = iterations;

this.message = message;

}

// Properties to retrieve configuration settings.

public int Iterations { get { return iterations; } }

public string Message { get { return message; } }

}

// A method that conforms to the System.Threading.WaitCallback delegate

// signature. Displays a message to the console.

public static void DisplayMessage(object state)

{

// Safely cast the state argument to a MessageInfo object.

MessageInfo config = state as MessageInfo;

// If the config argument is null, no arguments were passed to

// the ThreadPool.QueueUserWorkItem method; use default values.

if (config == null)

{

// Display a fixed message to the console three times.

for (int count = 0; count < 3; count++)

{

Console.WriteLine("A thread pool example.");

// Sleep for the purpose of demonstration. Avoid sleeping

// on thread-pool threads in real applications.

Thread.Sleep(1000);

}

}

else

{



152



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



// Display the specified message the specified number of times.

for (int count = 0; count < config.Iterations; count++)

{

Console.WriteLine(config.Message);

// Sleep for the purpose of demonstration. Avoid sleeping

// on thread-pool threads in real applications.

Thread.Sleep(1000);

}

}

}

public static void Main()

{

// Execute DisplayMessage using the thread pool and no arguments.

ThreadPool.QueueUserWorkItem(DisplayMessage);

// Create a MessageInfo object to pass to the DisplayMessage method.

MessageInfo info = new MessageInfo(5,

"A thread pool example with arguments.");

// Set the max number of threads.

ThreadPool.SetMaxThreads(2, 2);

// Execute DisplayMessage using the thread pool and providing an

// argument.

ThreadPool.QueueUserWorkItem(DisplayMessage, info);

// Wait to continue.

Console.WriteLine("Main method complete. Press Enter.");

Console.ReadLine();

}

}

}



Notes

Using the runtime’s thread pool simplifies multithreaded programming dramatically; however, be aware

that the implementation is a simple, general-purpose thread pool. Before deciding to use the thread

pool, consider the following points:





Each process has one thread pool, which supports by default a maximum of 25

concurrent threads per processor. You can change the maximum number of

threads using the method ThreadPool.SetMaxThreads, but some runtime hosts

(Internet Information Services [IIS] and SQL Server, for example) will limit the

maximum number of threads and may not allow the default value to be changed

at all.



153



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION







As well as allowing you to use the thread pool to execute code directly, the runtime

uses the thread pool for other purposes internally. This includes the asynchronous

execution of methods (see recipe 4-2), execution of timer events (see recipes 4-3

and 4-4), and execution of wait-based methods (see recipe 4-5). All of these uses

can lead to heavy contention for the thread-pool threads, meaning that the work

queue can become very long. Although the work queue’s maximum length is

limited only by the amount of memory available to the runtime’s process, an

excessively long queue will result in long delays before queued work items are

executed. The ThreadPool.GetAvailableThreads method returns the number of

threads currently available in the thread pool. This can be useful in determining

whether your application is placing too much load on the thread pool, indicating

that you should increase the number of available threads using the

ThreadPool.SetMaxThreads method.







Where possible, avoid using the thread pool to execute long-running processes.

The limited number of threads in the thread pool means that a handful of threads

tied up with long-running processes can significantly affect the overall

performance of the thread pool. Specifically, you should avoid putting thread-pool

threads to sleep for any length of time.







Thread-pool threads are background threads. You can configure threads as either

foreground threads or background threads. Foreground and background threads

are identical except that a background thread will not keep an application process

alive. Therefore, your application will terminate automatically when the last

foreground thread of your application terminates.







You have no control over the scheduling of thread-pool threads, and you cannot

prioritize work items. The thread pool handles each work item in the sequence in

which you add it to the work queue.







Once a work item is queued, it cannot be canceled or stopped.







Do not try to use thread-pool threads to directly update or manipulate Windows

Forms controls, because they can be updated only by the thread that created

them. Instead, use the controls’ Dispatcher property—see the .NET Framework

documentation for details.



4-2. Execute a Method Asynchronously

Problem

You need to start execution of a method and continue with other tasks while the method runs on a

separate thread. After the method completes, you need to retrieve the method’s return value.



Solution

Declare a delegate with the same signature as the method you want to execute. Create an instance of the

delegate that references the method. Call the BeginInvoke method of the delegate instance to start



154



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



executing your method. Use the EndInvoke method to determine the method’s status as well as obtain

the method’s return value if complete.



How It Works

Typically, when you invoke a method, you do so synchronously, meaning that the calling code blocks

until the method is complete. Most of the time, this is the expected, desired behavior because your code

requires the operation to complete before it can continue. However, sometimes it is useful to execute a

method asynchronously, meaning that you start the method in a separate thread and then continue with

other operations.

The .NET Framework implements an asynchronous execution pattern that allows you to call any

method asynchronously using a delegate. When you declare and compile a delegate, the compiler

automatically generates two methods that support asynchronous execution: BeginInvoke and EndInvoke.

When you call BeginInvoke on a delegate instance, the method referenced by the delegate is queued for

asynchronous execution. Control returns to the caller immediately, and the referenced method executes

in the context of the first available thread-pool thread.

The signature of the BeginInvoke method includes the same arguments as those specified by the

delegate signature, followed by two additional arguments to support asynchronous completion. These

additional arguments are as follows:





A System.AsyncCallback delegate instance that references a method that the

runtime will call when the asynchronous method completes. The method will be

executed by a thread-pool thread. Passing null means no method is called and

means you must use another mechanism (discussed later in this recipe) to

determine when the asynchronous method is complete.







A reference to an object that the runtime associates with the asynchronous

operation for you. The asynchronous method does not use or have access to this

object, but it is available to your code when the method completes, allowing you

to associate useful state information with an asynchronous operation. For

example, this object allows you to map results against initiated operations in

situations where you initiate many asynchronous operations that use a common

callback method to perform completion.



The EndInvoke method allows you to retrieve the return value of a method that was executed

asynchronously, but you must first determine when it has finished. If your asynchronous method threw

an exception, it will be rethrown so that you can handle it when you call EndInvoke. Here are the four

techniques for determining whether an asynchronous method has finished:





Blocking stops the execution of the current thread until the asynchronous method

completes execution. In effect, this is much the same as synchronous execution.

However, you have the flexibility to decide exactly when your code enters the

blocked state, giving you the opportunity to perform some additional processing

before blocking.



155



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

4-1. Execute a Method Using the Thread Pool

Tải bản đầy đủ ngay(0 tr)

×