1. Trang chủ
  2. » Công Nghệ Thông Tin

Professional C# 2008 phần 4 ppsx

185 342 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Professional C# 2008 phần 4 ppsx
Trường học University of Information Technology, Vietnam National University Ho Chi Minh City
Chuyên ngành Computer Science
Thể loại lecture notes
Năm xuất bản 2008
Thành phố Ho Chi Minh City
Định dạng
Số trang 185
Dung lượng 2,18 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

This section explores the following: What you can configure using the XML base configuration files How you can redirect a strong named referenced assembly to a different version How you

Trang 1

PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=msilehepg, Version=6.0.6000.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msilehepgdat, Version=6.0.6000.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msilehExtCOM, Version=6.0.6000.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msilehexthost, Version=6.0.6000.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msilehRecObj, Version=6.0.6000.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msilehshell, Version=6.0.6000.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msilEventViewer, Version=6.0.0.0, Culture=Neutral,

PublicKeyToken=31bf3856ad364e35, processorArchitecture=msil

If the security of the system changes, it ’ s not sure if the native image has the security requirements it needs for running the application This is why the native images become invalid with a system configuration change With the command ngen update all native images are rebuilt to include the new configurations

Installing CLR 2.0 runtime also installs the Native Image Service (or the Window Service CLR Optimization Service), with the name Microsoft NET Framework NGEN v2.0.50727_X86 This service can be used to defer compilation of native images and regenerates native images that have been invalidated

The command ngen install myassembly /queue can be used by an installation program to defer compilation of myassembly to a native image using the Native Image Service ngen update /queue regenerates all native images that have been invalidated With the ngen queue options pause ,

continue , and status you can control the service and get status information

You might ask why the native images cannot be created on the developer system, and you just distribute the native image to the production system The reason is that the native image generator takes care of the CPU that is installed with the target system and compiles the code optimized for the CPU type During installation of the application, the CPU is known

Configuring NET Applications

COM components used the registry to configure components Configuration of NET applications is done by using configuration files With registry configurations, an xcopy deployment is not possible

Configuration files can simply be copied The configuration files use XML syntax to specify startup and runtime settings for applications

This section explores the following:

What you can configure using the XML base configuration files How you can redirect a strong named referenced assembly to a different version How you can specify the directory of assemblies to find private assemblies in subdirectories and shared assemblies in common directories or on a server

Trang 2

Configuration Categories

The configuration can be grouped into these categories:

Startup settings enable you to specify the version of the required runtime It ’ s possible that

different versions of the runtime could be installed on the same system The version of the

runtime can be specified with the < startup > element

Runtime settings enable you to specify how garbage collection is performed by the runtime,

and how the binding to assemblies works You can also specify the version policy and the code

base with these settings You take a more detailed look into the runtime settings later in this

chapter

WCF settings are used to configure applications using WCF You deal with these configurations

in Chapter 42 , “ Windows Communication Foundation ”

Security settings are introduced in Chapter 20 , “ Security, ” and configuration for cryptography

and permissions is done there

These settings can be provided in three types of configuration files:

Application configuration files include specific settings for an application, such as binding

information to assemblies, configuration for remote objects, and so on Such a configuration file

is placed into the same directory as the executable; it has the same name as the executable with a

.config extension appended ASP.NET configuration files are named web.config

Machine configuration files are used for system - wide configurations You can also specify assembly

binding and remoting configurations here During a binding process, the machine configuration file

is consulted before the application configuration file The application configuration can override

settings from the machine configuration The application configuration file should be the preferred

place for application - specific settings so that the machine configuration file stays smaller and more

manageable A machine configuration file is located in %runtime_install_path%\config\

Machine.config

Publisher policy files can be used by a component creator to specify that a shared assembly is

compatible with older versions If a new assembly version just fixes a bug of a shared

component, it is not necessary to put application configuration files in every application

directory that uses this component; the publisher can mark it as compatible by adding a

publisher policy file instead In case the component doesn ’ t work with all applications, it is

possible to override the publisher policy setting in an application configuration file In contrast

to the other configuration files, publisher policy files are stored in the GAC

How are these configuration files used? How a client finds an assembly (also called binding ) depends on

whether the assembly is private or shared Private assemblies must be in the directory of the application

or in a subdirectory thereof A process called probing is used to find such an assembly If the assembly

doesn ’ t have a strong name, the version number is not used with probing

Shared assemblies can be installed in the GAC or placed in a directory, on a network share, or on a Web

site You specify such a directory with the configuration of the codeBase shortly The public key, version,

and culture are all important aspects when binding to a shared assembly The reference of the required

assembly is recorded in the manifest of the client assembly, including the name, the version, and the

public key token All configuration files are checked to apply the correct version policy The GAC and

code bases specified in the configuration files are checked, followed by the application directories,

and probing rules are then applied

Trang 3

Configuring Directories for Assembly Searches

You ’ ve already seen how to install a shared assembly to the GAC Instead of installing a shared assembly

to the GAC, you can configure a specific shared directory by using configuration files This feature can

be used if you want to make the shared components available on a server Another possible scenario arises if you want to share an assembly between your applications, but you don ’ t want to make it publicly available in the GAC, so you put it into a shared directory instead

There are two ways to find the correct directory for an assembly: the codeBase element in an XML configuration file, or through probing The codeBase configuration is available only for shared assemblies, and probing is done for private assemblies

< codeBase >

The < codeBase > can also be configured using the NET Configuration utility Code bases can be configured by selecting the properties of the configured application, SimpleShared , inside the Configured Assemblies in the Applications tree Similarly to the Binding Policy, you can configure lists of versions with the Codebases tab Figure 17 - 17 shows that the version 1.1 should be loaded from the Web server

http://www.christiannagel.com/WroxUtils

Figure 17 - 17 The NET Configuration utility creates this application configuration file:

Trang 4

< /dependentAssembly >

< /assemblyBinding >

< /runtime >

< /configuration >

The < codeBase > element has the attributes version and href With version , the original referenced

version of the assembly must be specified With href , you can define the directory from where the

assembly should be loaded In the example, a path using the HTTP protocol is used A directory on a

local system or a share is specified using href= “ file:C:/WroxUtils ”

Using that assembly loaded from the network causes a System.Security.Permissions exception

to occur You must configure the required permissions for assemblies loaded from the network In

Chapter 20 , “ Security, ” you learn how to configure security for assemblies

< probing >

When the < codeBase > is not configured and the assembly is not stored in the GAC, the runtime tries to

find an assembly through probing The NET runtime tries to find assemblies with either a dll or an

.exe file extension in the application directory, or in one of its subdirectories, that has the same name as

the assembly searched for If the assembly is not found here, the search continues You can configure

search directories with the < probing > element in the < runtime > section of application configuration

files This XML configuration can also be done easily by selecting the properties of the application with

the NET Framework Configuration tool You can configure the directories where the probing should

occur by using the search path in the NET Framework configuration (see Figure 17 - 18 )

Trang 5

A solution to this dilemma could be an architecture that allows installation of different versions of shared components, with clients using the version that they referenced during the build process This solves a lot of problems but not all of them What happens if you detect a bug in a component that ’ s referenced from the client? You would like to update this component and make sure that the client uses the new version instead of the version that was referenced during the build process

Therefore, depending on the type in the fix of the new version, you sometimes want to use a newer version, and you also want to use the older referenced version as well The NET architecture enables both scenarios

In NET, the original referenced assembly is used by default You can redirect the reference to a different version using configuration files Versioning plays a key role in the binding architecture — how the client gets the right assembly where the components live

Version Numbers

Assemblies have a four - part version number, for example, 1.1.400.3300 The parts are

< Major > < Minor > < Build > < Revision > How these numbers are used depends on your application configuration

A good policy is to change the major or minor number on changes incompatible with the previous version, but just the build or revision number with compatible changes This way, it can be assumed that redirecting an assembly to a new version where just the build and revision changed is safe

With Visual Studio 2008, you can define the version number of the assembly with the assembly information in the project settings The project settings write the assembly attribute

[AssemblyVersion] to the file AssemblyInfo.cs :

[assembly: AssemblyVersion(“1.0.0.0”)]

Trang 6

Instead of defining all four version numbers you can also place an asterisk in the third or fourth place:

[assembly: AssemblyVersion(“1.0.*”)]

With this setting, the first two numbers specify the major and minor version, and the asterisk ( * ) means

that the build and revision numbers are auto - generated The build number is the number of days since

January 1, 2000, and the revision is the number of seconds since midnight divided by two Though the

automatic versioning might help during development time, before shipping it is a good practice to

define a specific version number

This version is stored in the assembly section of the manifest

Referencing the assembly in the client application stores the version of the referenced assembly in the

manifest of the client application

Getting the Version Programmatically

To make it possible to check the version of the assembly that is used from the client application, add the

method GetAssemblyFullName() to the SharedDemo class created earlier to return the strong name of

the assembly For easy use of the Assembly class, you have to import the System.Reflection

The FullName property of the Assembly class holds the name of the class, the version, the locality,

and the public key token, as you see in the following output, when calling GetAssemblyFullName() in

your client application

In the client application, just add a call to GetAssemblyFullName() in the Main() method after

creating the shared component:

static void Main()

{

SharedDemo quotes = new

SharedDemo(@”C:\ProCSharp\Assemblies\Quotes.txt”);

Console.WriteLine(quotes.GetAssemblyFullName());

Be sure to register the new version of the shared assembly SharedDemo again in the GAC using

gacutil If the referenced version cannot be found, you will get a System.IO.FileLoadException ,

because the binding to the correct assembly failed

With a successful run, you can see the full name of the referenced assembly:

SharedDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7d886a6f7b9f0292

Press any key to continue

This client program can now be used to test different configurations of this shared component

Application Configuration Files

With a configuration file, you can specify that the binding should happen to a different version of a

shared assembly Assume that you create a new version of the shared assembly SharedDemo with

major and minor versions 1.1 Maybe you don ’ t want to rebuild the client but just want the new version

of the assembly to be used with the existing client instead This is useful in cases where either a bug is

fixed with the shared assembly or you just want to get rid of the old version because the new version is

compatible

Trang 7

Figure 17 - 19 shows the Global Assembly Cache Viewer, where the versions 1.0.0.0 and 1.0.3300.0 are installed for the SharedDemo assembly

This tool is shipped with Framework SDK and not with the NET runtime, so don ’ t expect this tool to be available to system administrators

Trang 8

Select Configured Assemblies in the tree view and the menu Action Add to configure the

dependency of the assembly SharedDemo from the dependency list Select the Binding Policy tab to

define the version that should be used as shown in Figure 17 - 23

Figure 17 - 21

When you select Applications on the left side, and then select Action Add, you can choose a NET

application to configure If the Client.exe application does not show up with the list, click the Other

button and browse to the executable Select the application Client.exe to create an application

configuration file for this application After adding the client application to the NET Configuration

utility, the assembly dependencies can be listed, as shown in Figure 17 - 22

Figure 17 - 22

Trang 9

Figure 17 - 23

For the requested version, specify the version referenced in the manifest of the client assembly

newVersion specifies the new version of the shared assembly In Figure 17 - 23 , it is specified that the version 1.0.3300.0 should be used instead of any version in the range of 1.0.0.0 to 1.0.3300.0

Now you can find the application configuration file Client.exe.config in the directory of the

Client.exe application that includes this XML code:

Runtime settings can be configured with the < runtime > element The subelement of < runtime > is

< assemblyBinding > , which in turn has a subelement < dependentAssembly > < dependentAssembly > has a required subelement < assemblyIdentity > You specify the name of the referenced assembly with

< assemblyIdentity > name is the only mandatory attribute for < assemblyIdentity > The optional attributes are publicKeyToken and culture The other subelement of < dependentAssembly > that ’ s needed for version redirection is < bindingRedirect > The old and the new versions of the dependent assembly are specified with this element

When you start the client with this configuration file, you will get the new version of the referenced shared assembly

Trang 10

Publisher Policy Files

Using assemblies shared from the GAC allows you to use publisher policies to override versioning

issues Assume that you have an assembly used by some applications What can be done if a critical bug

is found in the shared assembly? You have seen that it is not necessary to rebuild all the applications that

use this shared assembly, because you can use configuration files to redirect to the new version of this

shared assembly Maybe you don ’ t know all the applications that use this shared assembly, but you want

to get the bug fix to all of them In that case, you can create publisher policy files to redirect all

applications to the new version of the shared assembly

Publisher policy files apply only to shared assemblies installed in the GAC

To set up publisher policies, you have to do the following:

Create a publisher policy file

Create a publisher policy assembly

Add the publisher policy assembly to the GAC

Create a Publisher Policy File

A publisher policy file is an XML file that redirects an existing version or version range to a new version

The syntax used here is the same as for application configuration files, so you can use the same file you

created earlier to redirect the old versions 1.0.0.0 through 1.0.3300.0 to the new version 1.0.3300.0

Rename the previously created file to mypolicy.config to use it as a publisher policy file and remove

the element < publisherPolicy > :

Create a Publisher Policy Assembly

To associate the publisher policy file with the shared assembly, it is necessary to create a publisher policy

assembly, and to put it into the GAC The tool that can be used to create such files is the assembly linker

al The option /linkresource adds the publisher policy file to the generated assembly The name of

the generated assembly must start with policy, followed by the major and minor version number of the

assembly that should be redirected, and the file name of the shared assembly In this case the publisher

policy assembly must be named policy.1.0.SharedDemo.dll to redirect the assemblies SharedDemo

with the major version 1 and minor version 0 The key that must be added to this publisher key with the

option /keyfile is the same key that was used to sign the shared assembly SharedDemo to guarantee

that the version redirection is from the same publisher

Trang 11

al /linkresource:mypolicy.config /out:policy.1.0.SharedDemo.dll /keyfile: \ \mykey.snk

Add the Publisher Policy Assembly to the GAC

The publisher policy assembly can now be added to the GAC with the utility gacutil :

gacutil -i policy.1.0.SharedDemo.dll

Now remove the application configuration file that was placed in the directory of the client application and start the client application Although the client assembly references 1.0.0.0, you use the new version 1.0.3300.0 of the shared assembly because of the publisher policy

Overriding Publisher Policies

With a publisher policy, the publisher of the shared assembly guarantees that a new version of the assembly is compatible with the old version As you know, from changes of traditional DLLs, such guarantees don ’ t always hold Maybe all except one application is working with the new shared assembly To fix the one application that has a problem with the new release, the publisher policy can be overridden by using an application configuration file

With the NET Framework Configuration tool you can override the publisher policy by deselecting the Enable Publisher Policy check box, as shown in Figure 17 - 24

Trang 12

Installing and using multiple versions is not only possible with assemblies but also with the NET

runtime (CLR) The versions 1.0, 1.1, and 2.0 (and later versions) of the CLR can be installed on the same

operating system side by side Visual Studio 2008 targets applications running on CLR 2.0 with NET 2.0,

3.0, and 3.5 With CLR 2.0 the assembly file format changed, so it is not possible to run CLR 2.0

applications with CLR 1.1

If the application is built with CLR 1.1, it is possible to target systems that have only the CLR 1.0 runtime

installed The same can be expected about future minor releases in that they can target CLR 2.0 runtime

versions

An application that was built using CLR 1.0 may run without changes on CLR 1.1 If an operating system

has both versions of the runtime installed, the application will use the version with which it was built

However, if only version 1.1 is installed with the operating system, and the application was built with

version 1.0, it tries to run with the newer version There ’ s a good chance the application runs without

problems The registry key HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\policy

lists the ranges of the versions that will be used for a specific runtime

If an application was built using NET 1.1, it may run without changes on NET 1.0, in case no classes or

methods are used that are available only with NET 1.1 Here an application configuration file is needed

to make this possible

In an application configuration file, it ’ s not only possible to redirect versions of referenced assemblies;

you can also define the required version of the runtime Different NET runtime versions can be installed

on a single machine You can specify the version that ’ s required for the application in an application

configuration file The element < supportedVersion > marks the runtime versions that are supported by

There is one major point in case you still have NET 1.0 applications that should run on NET 1.1 runtime

versions The element < supportedVersion > was new with NET 1.1 .NET 1.0 used the element

< requiredRuntime > to specify the needed runtime So for NET 1.0 applications, both configurations

must be done as shown here:

< ?xml version=”1.0”? >

< configuration >

< startup >

(continued)

Trang 13

You learned the differences between private and shared assemblies and saw how shared assemblies can

be created With private assemblies, you don ’ t have to pay attention to uniqueness and versioning issues because these assemblies are copied and only used by a single application Sharing assemblies requires you to use a key for uniqueness and to define the version You looked at the GAC, which can be used as

an intelligent store for shared assemblies

You can have faster application startups by using the native image generator With this the JIT compiler does not need to run because the native code is created during installation time

You looked at overriding versioning issues to use a version of an assembly different from the one that was used during development; this is done through publisher policies and application configuration files Finally, you learned how probing works with private assemblies

The chapter also discussed loading assemblies dynamically and creating assemblies during runtime

If you want to get more information on this, you should read Chapter 36 about the Add - In model of

.NET 3.5

Trang 15

Tracing and Events

Chapter 14 covered errors and exception handling Besides handling exceptional code, it might

be really interesting to get some live information about your running application to find the reason for some issues that application might have during production, or to monitor resources needed to early adapt to higher user loads This is where the namespace System.Diagnostics comes into play

The application doesn ’ t throw exceptions, but sometimes it doesn ’ t behave as expected The application might be running well on most systems but might have a problem on a few On the live system, you change the log behavior by changing a configuration value and get detailed live

information about what ’ s going on in the application This can be done with tracing

If there are problems with applications, the system administrator needs to be informed With the Event Viewer, the system administrator both interactively monitors problems with applications

and gets informed about specific events that happen by adding subscriptions The event - logging

mechanism allows you to write information about the application

To analyze resources needed from applications, monitor applications with specified time intervals, and plan for a different application distribution or extending of system resources, the system administrator uses the performance monitor You can write live data of your application using

With tracing you can see messages from the running application To get some information about a running application, you can start the application in the debugger During debugging, you can walk through the application step by step and set breakpoints at specific lines and when you reach

Trang 16

specific conditions The problem with debugging is that a released program can behave differently For

example, while the program is stopping at a breakpoint, other threads of the application are suspended

as well Also, with a release build, the compiler - generated output is optimized and thus different effects

can occur There is a need to have information from a release build as well Trace messages are written

both with debug and release code

A scenario showing how tracing helps is described here After an application is deployed, it runs on

one system without problems, while on another system intermediate problems occur Turning on

verbose tracing on the system with the problems gives you detailed information about what ’ s

happening inside the application The system that is running without problems has tracing configured

just for error messages redirected to the Windows event log system Critical errors are seen by the

system administrator The overhead of tracing is very small, because you configure a trace level only

when needed

The tracing architecture has four major parts:

The source is the originator of the trace information You use the source to send trace messages

The switch defines the level of information to log For example, you can request just error

information or detailed verbose information

Trace listeners define where the trace messages should be written

Listeners can have filters attached The filter defines what trace messages should be written by

the listener This way, you can have different listeners for the same source that write different

levels of information

Figure 18 - 1 shows the major classes for tracing and how they are connected in a Visual Studio class

diagram The TraceSource uses a switch to define what information to log The TraceSource has a

TraceListenerCollection associated where trace messages are forwarded to The collection consists

of TraceListener objects, and every listener has a TraceFilter connected

Figure 18-1

Trang 17

Trace Sources

You can write trace messages with the TraceSource class Tracing requires the Trace flag of the compiler settings With a Visual Studio project, the Trace flag is set by default with debug and release builds, but you can change it through the Build properties of the project

The TraceSource class is more difficult to use compared to the Trace class writing trace messages, but it provides more options

To write trace messages, you need to create a new TraceSource instance In the constructor, the name of the trace source is defined The method TraceInformation() writes an information message to the trace output Instead of just writing informational messages, the TraceEvent() method requires an enumeration value of type TraceEventType to define the type of the trace message TraceEventType.Error specifies the message as an error message You can define it with a trace switch to see only error messages The second argument of the TraceEvent() method requires an identifier The ID can be used within the application itself For example, you can use id 1 for entering a method and id 2 for exiting a method The method TraceEvent() is overloaded, so the TraceEventType and the ID are the only required parameters Using the third parameter of an overloaded method, you can pass the message written to the trace TraceEvent() also supports passing a format string with any number of parameters in the same way as Console.WriteLine() TraceInformation() does nothing more than invoke TraceEvent() with an identifier of 0 TraceInformation() is just a simplified version of

TraceEvent() With the TraceData() method, you can pass any object, for example an exception instance, instead of a message To make sure that data is written by the listeners and does not stay in memory, you need to do a Flush() If the source is no longer needed, you can invoke the Close() method that closes all listeners associated with the trace source Close() does a Flush() as well

TraceSource source1 = new TraceSource(“Wrox.ProCSharp.Tracing”);

source1.TraceInformation(“Info message”);

source1.TraceEvent(TraceEventType.Error, 3, “Error message”);

source1.TraceData(TraceEventType.Information, 2, new int[] { 1, 2, 3 });

source1.Flush();

source1.Close();

You can use different trace sources within your application It makes sense to define different sources for different libraries, so that you can turn on different trace levels for different parts of your application To use a trace source you need to know its name A commonly used name for the trace source is the same name as the namespace

The TraceEventType enumeration that is passed as an argument to the TraceEvent() method defines the following levels to specify the severity of the problem: Verbose , Information , Warning ,

Error , and Critical Critical defines a fatal error or application crash; Error defines a recoverable error Trace messages at the Verbose level give you detailed debugging information TraceEventType also defines action levels Start , Stop , Suspend , and Resume These levels define timely events inside a logical operation

The code, as it is written now, does not display any trace message because the switch associated with the trace source is turned off

Trang 18

Trace Switches

To enable or disable trace messages, you can configure a trace switch Trace switches are classes that are

derived from the abstract base class Switch Derived classes are BooleanSwitch , TraceSwitch , and

SourceSwitch The class BooleanSwitch can be turned on and off, and the other two classes provide a

range level that is defined by the TraceLevel enumeration To configure trace switches, you must know

the values associated with the TraceLevel enumeration TraceLevel defines the values Off , Error ,

Warning , Info , and Verbose

You can associate a trace switch programmatically by setting the Switch property of the TraceSource

Here the switch associated is of type SourceSwitch , has the name MySwitch , and has the level

Verbose :

TraceSource source1 = new TraceSource(“Wrox.ProCSharp.Tracing”);

source1.Switch = new SourceSwitch(“MySwitch”, “Verbose”);

Setting the level to Verbose means that all trace messages should be written If you set the value to

Error , only error messages should show up Setting the value to Information means that error,

warning, and info messages are shown Writing the trace messages once more, you can see the messages

while running the debugger in the Output window

Usually, you would want to change the switch level not by recompiling the application, but instead by

changing the configuration The trace source can be configured in the application configuration file

Tracing is configured within the < system.diagnostics > element The trace source is defined with the

< source > element as a child element of < sources > The name of the source in the configuration file

must exactly match the name of the source in the program code Here, the trace source has a switch of

type System.Diagnostics.SourceSwitch associated with the name MySourceSwitch The switch

itself is defined within the < switches > section, and the level of the switch is set to verbose

Now, you can change the trace level just by changing the configuration file without the need to

recompile the code After the configuration file is changed, you must restart the application

Currently, trace messages are written to just the Output window of Visual Studio while you are running

it in a debug session Adding trace listeners changes this

Trace Listeners

By default, trace information is written to the Output window of the Visual Studio debugger Just by

changing the application configuration, you can redirect the trace output to different locations

Where tracing should be written to is defined by trace listeners A trace listener is derived from the

abstract base class TraceListener

Trace listeners defined by the NET Framework are described in the following table

Trang 19

Trace Listener Description

DefaultTraceListener A default trace listener is automatically added to the listeners

collection of the Trace class Default output goes to the attached debugger In Visual Studio, this is shown in the Output window during a debugging session

EventLogTraceListener The EventLogTraceListener writes trace information to the

event log With the constructor of the

EventLogTraceListener , you can specify an event log source

or an object of type EventLog Event logging is described later

in this chapter

TextWriterTraceListener With the TextWriterTraceListener trace, output can be

writ-ten to a file, a TextWriter , or a Stream See Chapter 25 , “ Manipulating Files and the Registry, ” for file manipulation information

Text WriterTraceListener is the base class of

ConsoleTraceListener , DelimitedListTraceListener , and XmlWriterTraceListener

ConsoleTraceListener ConsoleTraceListener writes trace messages to the console

DelimitedListTraceListener DelimitedListTraceListener writes trace messages to a

delimited file With trace output options, you can define a lot of separate tracing information such as process ID, time, and the like, which can be read more easily with a delimited file

XmlWriterTraceListener Instead of using a delimited file, you can redirect the trace

infor-mation to an XML file with the XmlWriterTraceListener

IisTraceListener The IisTraceListener was added in NET 3.0

WebPageTraceListener ASP.NET has another tracing option to get ASP.NET trace

infor-mation about Web pages in a dynamically created output file

trace axd If you configure the WebPageTraceListener , then

System.Diagnostics trace information goes into trace.axd

to your phone in your spare time And with verbose tracing this can become really expensive

You can configure a trace listener programmatically by creating a listener object and assigning it to the

Listeners property of the TraceSource class However, usually it is more interesting to just change a configuration to define a different listener

You can configure listeners as child elements of the < source > element With the listener, you define the type of the listener class and use initializeData to specify where the output of the listener should

go The configuration here defines the XmlWriterTraceListener to write to the file demotrace.xml and the DelimitedListTraceListener to write to the file demotrace.txt :

Trang 20

You might get a warning from the XML schema regarding the delimiter attribute declaration You

can ignore it

With the listener, you can also specify what additional information should be written to the trace

log This information is defined with the traceOutputOptions XML attribute and is defined

by the TraceOptions enumeration The enumeration defines Callstack , DateTime ,

LogicalOperationStack , ProcessId , ThreadId , and None The information needed can

be added with comma separation to the traceOutputOptions XML attribute, as shown with the

delimited trace listener

The delimited file output from the DelimitedListTraceListener , including the process ID and date/

time, is shown here:

“Wrox.ProCSharp.Tracing”:Information:0:”Info message”::4188:””::

“2007-01-23T12:38:31.3750000Z”::

“Wrox.ProCSharp.Tracing”:Error:3:”Error message”::4188:””::

“2007-01-23T12:38:31.3810000Z”::

The XML output from the XmlWriterTraceListener always contains the name of the computer, the

process ID, the thread ID, the message, the time created, the source, and the activity ID Other fields,

such as the call stack, logical operation stack, and timestamp, depend on the trace output options

You can use the XmlDocument and XPathNavigator classes to analyze the content from the XML

file These classes are covered in Chapter 28 , “ Manipulating XML ”

If a listener should be used by multiple trace sources, you can add the listener configuration to the

element < sharedListeners > , which is independent of the trace source The name of the listener that is

configured with a shared listener must be referenced from the listeners of the trace source:

< ?xml version=”1.0” encoding=”utf-8” ? >

< configuration >

< system.diagnostics >

< sources >

Trang 21

A filter is a class that is derived from the abstract base class TraceFilter NET 3.0 offers two filter implementations: SourceFilter and EventTypeFilter With the source filter, you can specify that trace messages are to be written only from specific sources The event type filter is an extension to the switch functionality With a switch, it is possible to define, according to the trace severity level, if the event source should forward the trace message to the listeners If the trace message is forwarded, the listener now can use the filter to decide if the message should be written

The changed configuration now defines that the delimited listener should write trace messages only if the severity level is of type warning or higher, because of the defined EventTypeFilter The XML listener specifies a SourceFilter and accepts trace messages only from the source

Wrox.ProCSharp.Tracing In case you have a large number of sources defined to write trace messages to the same listener, you can change the configuration for the listener to concentrate on trace messages from a specific source

Trang 22

The tracing architecture can be extended Just as you can write a custom listener derived from the base

class TraceListener , you can also create a custom filter derived from TraceFilter With that

capability, you can create a filter that specifies to write trace messages, for example, depending on the

time, depending on an exception that occurred lately, or depending on the weather

Asserts

Another feature that belongs to tracing are asserts Asserts are critical problems within the program path

With asserts, a message is displayed with the error, and you can abort or continue the application

Asserts are very helpful when you write a library that is used by another developer

With the Foo() method, Trace.Assert() examines parameter o to see if it is not null If the condition

is false , the error message as shown in Figure 18 - 2 is issued If the condition is true , the program

(continued)

Figure 18-2

Trang 23

continues The Bar() method includes a Trace.Assert() example where it is verified that the parameter is larger than 10 and smaller than 20 If the condition is false , an error message is shown again

static void Foo(object o) {

Trace.Assert(o != null, “Expecting an object”);

Console.WriteLine(o);

} static void Bar(int x) {

Trace.Assert(x > 10 & & x < 20, “x should be between 10 and 20”);

Console.WriteLine(x);

} static void Main() {

Trace messages can be written to the event log if you configure the EventLogTraceListener class The

EventLogTraceListener has an EventLog object associated with it to write the event log entry You can also use the EventLog class directly to write and read event logs

In this section, you explore the following:

❑ Event - logging architecture

❑ Classes for event logging from the System.Diagnostics namespace

❑ Adding event logging to services and to other application types

❑ Creating an event log listener with the EnableRaisingEvents property of the EventLog class Figure 18 - 3 shows an example of a log entry from a modem

Trang 24

For custom event logging, you can use classes from the System.Diagnostics namespace

Event - Logging Architecture

The event log information is stored in several log files The most important ones are application, security,

and system Looking at the registry configuration of the event log service, you will notice several entries

under HKEY _ LOCAL _ MACHINE\System\CurrentControlSet\Services\Eventlog with configurations

pointing to the specific files The system log file is used from the system and device drivers Applications

and services write to the application log The security log is a read - only log for applications The

audit-ing feature of the operataudit-ing system uses the security log Every application can also create a custom

category and log file to write event log entries there For example, this is done by Windows OneCare and

Media Center

You can read these events by using the administrative tool Event Viewer The Event Viewer can be

started directly from the Server Explorer of Visual Studio by right - clicking the Event Logs item and

selecting the Launch Event Viewer entry from the context menu The Event Viewer is shown in

Figure 18 - 4

In the event log, you can see this information:

Type — The type can be Information, Warning, or Error Information is an infrequent successful

operation; Warning is a problem that is not immediately significant; and Error is a major

problem Additional types are FailureAudit and SuccessAudit, but these types are used only for

the security log

Date — Date and Time show the time when the event occurred

Figure 18-3

Trang 25

Source — The Source is the name of the software that logs the event The source for the

applica-tion log is configured in:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Eventlog\Application\

[ApplicationName]

Below this key, the value EventMessageFile is configured to point to a resource DLL that holds error messages

Category — A Category can be defined so that event logs can be filtered when using the Event

Viewer Categories can be defined by an event source

Event identifier — The Event identifier specifies a particular event message

Event - Logging Classes

The System.Diagnostics namespace has some classes for event logging, which are shown in the following table

Class Description

EventLog With the EventLog class, you can read and write entries in the event

log, and establish applications as event sources

EventLogEntry The EventLogEntry class represents a single entry in the event log

With the EventLogEntryCollection , you can iterate through

EventLogEntry items

Figure 18-4

Trang 26

Class Description

EventLogInstaller The EventLogInstaller class is the installer for an EventLog

component EventLogInstaller calls EventLog.CreateEventSource() to create an event source

EventLogTraceListener With the help of the EventLogTraceListener , traces can be written

to the event log This class implements the abstract class

Entries With the Entries property, you can read event logs Entries

returns an EventLogEntryCollection that contains

EventLogEntry objects holding information about the events

There is no need to invoke a Read() method The collection is filled as soon as you access this property

Log property

LogDisplayName LogDisplayName is a read - only property that returns the display

name of the log

MachineName With the MachineName , you can specify the system on which to

read or write log entries

Source The Source property specifies the source of the event entries

to write

CreateEventSource() The CreateEventSource() creates a new event source and a

new log file, if a new log file is specified with this method

DeleteEventSource() To get rid of an event source, you can invoke

DeleteEventSource()

SourceExists() Before creating an event source, you can verify if the source

already exists by using this element

WriteEntry()WriteEvent() Write event log entries with either the WriteEntry() or

WriteEvent() method WriteEntry() is simpler, because you just need to pass a string WriteEvent() is more flexible, because you can use message files that are independent of the application and that support localization

Trang 27

Creating an Event Source

Before writing events, you must create an event source You can use either the CreateEventSource() method of the EventLog class or the class EventLogInstaller Because you need administrative privileges when creating an event source, an installation program would be best for defining the new source

Chapter 16 , “ Deployment, ” explains how to create installation programs

The following sample verifies that an event log source named EventLogDemoApp already exists If it doesn ’ t exist, an object of type EventSourceCreationData is instantiated that defines the source name

EventLogDemoApp and the log name ProCSharpLog Here, all events of this source are written to the

ProCSharpLog event log The default is the application log

if (!EventLog.SourceExists(“EventLogDemoApp”)) {

EventSourceCreationData eventSourceData = new EventSourceCreationData(“EventlogDemoApp”, “ProCSharpLog”);

EventLog.CreateEventSource(eventSourceData);

}

The name of the event source is an identifier of the application that writes the events For the system administrator reading the log, the information helps in identifying the event log entries to map them to application categories Examples of names for event log sources are LoadPerf for the performance monitor, MSSQLSERVER for Microsoft SQL Server, MsiInstaller for the Windows Installer, Winlogon ,

Tcpip , Time - Service , and so on

Setting the name Application for the event log writes event log entries to the application log You can also create your own log by specifying a different application log name Log files are located in the directory < windows > \System32\WinEvt\Logs

With the EventSourceCreationData , you can also specify several more characteristics for the event log, as shown in the following table

EventSourceCreationData Description

Source The property Source gets or sets the name of the event source

LogName LogName defines the log where event log entries are written The

default is the application log

MachineName With MachineName , you can define the system to read or write log

entries

CategoryResourceFile With the CategoryResourceFile property, you can define a

resource file for categories Categories can be used for an easier ing of event log entries within a single source

CategoryCount The CategoryCount property defines the number of categories in the

category resource file

Trang 28

EventSourceCreationData Description

MessageResourceFile Instead of specifying that the message should be written to the event

log in the program that writes the events, messages can be defined in

a resource file that is assigned to the MessageResourceFile erty Messages from the resource file are localizable

ParameterResourceFile Messages in a resource file can have parameters The parameters can

be replaced by strings defined in a resource file that is assigned to the

ParameterResourceFile property

Writing Event Logs

For writing event log entries, you can use the WriteEntry() or WriteEvent() methods of the

EventLog class

The EventLog class has both a static and an instance method WriteEntry() The static method

WriteEntry() requires a parameter of the source The source can also be set with the constructor of

the EventLog class Here in the constructor, the log name, the local machine, and the event source name

are defined Next, three event log entries are written with the message as the first parameter of the

WriteEntry() method WriteEntry() is overloaded The second parameter you can assign is an

enumeration of type EventLogEntryType With EventLogEntryType , you can define the severity of

the event log entry Possible values are Information , Warning , and Error , and for auditing

SuccessAudit and FailureAudit Depending on the type, different icons are shown in the Event

Viewer With the third parameter, you can specify an application - specific event ID that can be used by

the application itself In addition to that, you can also pass application - specific binary data and

Instead of defining the messages for the event log in the C# code and passing it to the WriteEntry()

method, you can create a message resource file , define messages in the resource file, and pass message

identifiers to the WriteEvent() method Resource files also support localization

Message resource files are native resource files that have nothing in common with NET resource files

.NET resource files are covered in Chapter 21 , “ Localization ”

A message file is a text file with the mc file extension The syntax that this file uses to define messages is

very strict The sample file EventLogMessages.mc contains four categories followed by event messages

Every message has an ID that can be used by the application writing event entries Parameters that can

be passed from the application are defined with % syntax in the message text

Trang 29

For the exact syntax of message files, check the MSDN documentation for Message Text Files

Installation

MessageId=0x2Severity=SuccessSymbolicName=DATA_CATEGORYLanguage=English

Database Query

MessageId=0x3Severity=SuccessSymbolicName=UPDATE_CATEGORYLanguage=English

Data Update

MessageId=0x4Severity=SuccessSymbolicName=NETWORK_CATEGORYLanguage=English

Network Communication

; // Event messages

-; // *********************************

MessageId = 1000Severity = SuccessFacility = ApplicationSymbolicName = MSG_CONNECT_1000Language=English

Connection successful

MessageId = 1001Severity = ErrorFacility = ApplicationSymbolicName = MSG_CONNECT_FAILED_1001Language=English

Could not connect to server %1

Trang 30

; // Event message parameters

-; // Language independent insertion strings

Use the Messages Compiler, mc.exe , to create a binary message file mc – s EventLogDemoMessages

.mc compiles the source file containing the messages to a messages file with the bin extension and the

file Messages.rc , which contains a reference to the binary message file:

mc -s EventLogDemoMessages.mc

Next, you must use the Resource Compiler, rc.exe rc EventLogDemoMessages.rc creates the

resource file EventLogDemoMessages.RES :

rc EventLogDemoMessages.rc

With the linker, you can bind the binary message file EventLogDemoMessages.RES to a native DLL:

link /DLL /SUBSYSTEM:WINDOWS /NOENTRY /MACHINE:x86 EventLogDemoMessages.RES

(continued)

Trang 31

Now, you can register an event source that defines the resource files as shown in the following code

First, a check is done if the event source named EventLogDemoApp exists If the event log must be created because it does not exist, the next check verifies if the resource file is available Some samples in the MSDN documentation demonstrate writing the message file to the < windows > \system32 directory, but you shouldn ’ t do that Copy the message DLL to a program - specific directory that you can get with the SpecialFolder enumeration value ProgramFiles If you need to share the messages file among multiple applications, you can put it into Environment.SpecialFolder.CommonProgramFiles If the file exists, a new object of type EventSourceCreationData is instantiated In the constructor, the name

of the source and the name of the log are defined You use the properties CategoryResourceFile ,

MessageResourceFile , and ParameterResourceFile to define a reference to the resource file After the event source is created, you can find the information on the resource files in the registry with the event source The method CreateEventSource registers the new event source and log file Finally, the method RegisterDisplayName() from the EventLog class specifies the name of the log as it is displayed in the Event Viewer The ID 5001 is taken from the message file

If you want to delete a previously created event source, you can do so with EventLog.DeleteEventSource(sourceName); To delete a log, you can invoke EventLog.Delete(logName);

string logName = “ProCSharpLog”;

string sourceName = “EventLogDemoApp”;

string resourceFile = Environment.GetFolderPath(

Environment.SpecialFolder.ProgramFiles) + @”\procsharp\EventLogDemoMessages.dll”;

if (!EventLog.SourceExists(sourceName)) {

if (!File.Exists(resourceFile)) {

Console.WriteLine(“Message resource file does not exist”);

return;

} EventSourceCreationData eventSource = new EventSourceCreationData(sourceName, logName);

eventSource.CategoryResourceFile = resourceFile;

eventSource.CategoryCount = 4;

eventSource.MessageResourceFile = resourceFile;

eventSource.ParameterResourceFile = resourceFile;

EventLog.CreateEventSource(eventSource);

} else { logName = EventLog.LogNameFromSourceName(sourceName, “.”);

} EventLog evLog = new EventLog(logName, “.”, sourceName);

evLog.RegisterDisplayName(resourceFile, 5001);

Now, you can use the WriteEvent() method instead of WriteEntry() to write the event log entry

WriteEvent() requires an object of type EventInstance as parameter With the EventInstance , you can assign the message ID, the category, and the severity of type EventLogEntryType In addition to the

EventInstance parameter, WriteEvent() accepts parameters for messages that have parameters and binary data as byte array

Trang 32

EventLog log = new EventLog(logName, “.”, sourceName);

EventInstance info1 = new EventInstance(1000, 4,

For the message identifiers, it is useful to define a class with const values that provide a more

meaning-ful name for the identifiers in the application

You can read the event log entries with the Event Viewer

Event Log Listener

Instead of using the Event Viewer to read event log entries, you can create a custom event log reader that

listens for events of specified types as needed You can create a reader where important messages pop up

to the screen, or send SMS to a system administrator

Next, you write an application that receives an event when a service encounters a problem Create a

simple Windows application that monitors the events of your Quote service This Windows application

consists of a list box and an Exit button only, as shown in Figure 18 - 5

Figure 18-5

Add an EventLog component to the design view by dragging and dropping it from the toolbox Set the

Log property to Application You can set the Source property to a specific source to receive event log

entries from only this source, for example the source EventLogDemoApp for receiving the event logs

from the application created previously If you leave the Source property empty, you will receive

Trang 33

events from every source You also need to change the property EnableRaisingEvents The default value is false ; setting it to true means that an event is generated each time this event occurs, and you can add an event handler for the EntryWritten event of the EventLog class Add a handler with the name OnEntryWritten() to this event

The OnEntryWritten() handler receives an EntryWrittenEventArgs object as argument, from which you can get the complete information about an event With the Entry property, an EventLogEntry object with information about the time, event source, type, category, and so on is returned:

protected void OnEntryWritten (object sender, System.Diagnostics.EntryWrittenEventArgs e) {

StringBuilder sb = new StringBuilder();

sb.AppendFormat(“{0} {1} {2}”, e.Entry.TimeGenerated.ToShortTimeString(), e.Entry.Source,

Microsoft Windows has many performance objects, such as System , Memory , Objects , Process ,

Processor , Thread , Cache , and so on Each of these objects has many counts to monitor For example, with the Process object, the user time, handle count, page faults, thread count, and so on can be monitored for all processes or for specific process instances Some applications, such as SQL Server, also add application - specific objects

For the quote service sample application, it might be interesting to get information about the number of client requests, the size of the data sent over the wire, and so on

Figure 18-6

Trang 34

Performance - Monitoring Classes

The System.Diagnostics namespace provides these classes for performance monitoring:

❑ PerformanceCounter can be used both to monitor counts and to write counts New

performance categories can also be created with this class

❑ PerformanceCounterCategory enables you to step through all existing categories as well as

create new ones You can programmatically get all the counters in a category

❑ PerformanceCounterInstaller is used for the installation of performance counters Its use is

similar to that of the EventLogInstaller discussed previously

Performance Counter Builder

The sample application is a simple Windows application with just one button so that you can see how

to write performance counts In a similar way, you can add performance counters to a Windows

Service (see Chapter 23 , “ Windows Services ” ), to a network application (see Chapter 41 , “ Accessing

the Internet ” ), or to any other application from which you would like to receive live counts

Using Visual Studio, you can create a new performance counter category by selecting the performance

counters in the Server Explorer and by selecting the menu entry Create New Category on the context

menu This launches the Performance Counter Builder (see Figure 18 - 7 )

Figure 18-7

Trang 35

Set the name of the performance counter category to Wrox Performance Counters The following table shows all performance counters of the quote service

# of Button clicks Total # of button clicks NumberOfItems32 # of Button clicks/sec # of button clicks in one second RateOfCountsPerSecond32 # of Mouse move events Total # of mouse move events NumberOfItems32

# of Mouse move events/sec # of mouse move events in one

Adding PerformanceCounter Components

Now you can add PerformanceCounter components from the toolbox Instead of using the components from the toolbox category Components, you can directly drag and drop the previously created performance counters from the Server Explorer to the design view This way, the instances are configured automatically; the CategoryName property is set to “ Wrox Performance Counters ” for all objects, and the CounterName property is set to one of the values available in the selected category

Because with this application the performance counts will not be read but written, you must set the

ReadOnly property to false Also, set the MachineName property to so that the application writes performance counts locally

Here is a part of the code generated into InitalizeComponent() by adding the PerformanceCounter components to the Designer and by setting the properties as indicated previously:

private void InitializeComponent() {

//

//

// performanceCounterButtonClicks //

this.performanceCounterButtonClicks.CategoryName = “Wrox Performance Counts”;

this.performanceCounterButtonClicks.CounterName = “# of Button Clicks”;

this.performanceCounterButtonClicks.ReadOnly = false;

//

// performanceCounterButtonClicksPerSec //

this.performanceCounterButtonClicksPerSec.CategoryName = “Wrox Performance Counts”;

this.performanceCounterButtonClicksPerSec.CounterName = “# of Button Clicks / sec”;

(continued)

Trang 36

For the calculation of the performance values, you need to add the fields clickCountPerSec and

mouseMoveCountPerSec to the class Form1 :

public partial class Form1 : Form

{

// Performance monitoring counter values

private int clickCountPerSec = 0;

private int mouseMoveCountPerSec = 0;

Add an event handler to the Click event of the button and an event handler to the MouseMove event to

the form, and add the following code to the handlers:

private void button1_Click(object sender, EventArgs e)

The Increment() method of the PerformanceCounter object increments the counter by one If you

need to increment the counter by more than one, for example to add information about a byte count

sent or received, you can use the IncrementBy() method For the performance counts that show

the value in seconds, just the two variables, clickCountPerSec and mouseMovePerSec , are

incremented

To show updated values every second, add a Timer component Set the OnTimer() method to the

Elapsed event of this component The OnTimer() method is called once per second if you set

the Interval property to 1000 In the implementation of this method, set the performance counts by

using the RawValue property of the PerformanceCounter class:

(continued)

Trang 37

protected void OnTimer (object sender, System.Timers.ElapsedEventArgs e) {

performanceCounterButtonClicksPerSec.RawValue = clickCountPerSec;

clickCountPerSec = 0;

performanceCounterMouseMoveEventsPerSec.RawValue = mouseMoveCountPerSec;

mouseMoveCountPerSec = 0;

}

The timer must be started:

public Form1() {

InitializeComponent();

this.timer1.Start();

Figure 18-8

Trang 38

Summar y

In this chapter, you have seen tracing and logging facilities that can help you find intermediate problems

in your applications You should plan early, building these features into your applications This will help

you avoid many troubleshooting problems later

With tracing, you can write debugging messages to an application that can also be used for the final

product delivered In case there are problems, you can turn tracing on by changing configuration values,

and find the issues

Event logging provides information to the system administrator to help find some of the critical issues

with the application Performance monitoring helps in analyzing the load from applications and in

planning in advance for resources that might be required in the future

In the next chapter you learn all about writing multithreaded applications

Figure 18-9

After you have added the counters to the performance monitor, you can see the actual values of the

service over time (see Figure 18 - 9 ) Using this performance tool, you can also create log files to analyze

the performance at a later time

Trang 39

Threading and Synchronization

There are several reasons for using threading Suppose that you are making a network call from an application that might take some time You don ’ t want to stall the user interface and just let the user wait until the response is returned from the server The user could do some other actions in the meantime or even cancel the request that was sent to the server Using threads can help

For all activities that require a wait — for example, because of a file, database, or network access —

a new thread can be started to fulfill other tasks at the same time Even if you have only processing - intensive tasks to do, threading can help Multiple threads of a single process can run

on different CPUs, or, nowadays, on different cores of a multiple - core CPU, at the same time

You must be aware of some issues when running multiple threads, however Because they can run during the same time, you can easily get into problems if the threads access the same data You must implement synchronization mechanisms

This chapter provides the foundation you will need when programming applications with multiple threads, including:

An overview of threading Lightweight threading using delegates Thread class

Thread pools Threading issues Synchronization techniques Timers

COM apartments Event - based asynchronous pattern

Trang 40

Over view

A thread is an independent stream of instructions in a program All your C# programs up to this point

have one entry point — the Main() method Execution starts with the first statement in the Main()

method and continues until that method returns

This program structure is all very well for programs, in which there is one identifiable sequence of tasks,

but often a program needs to do more than one thing at the same time Threads are important both for

client - side and for server - side applications While you type C# code in the Visual Studio editor, the

Dynamic Help window immediately shows the topics that fit to the code you type A background thread

is searching through help The same thing is done by the spell checker in Microsoft Word One thread is

waiting for input from the user, while the other does some background research A third thread can store

the written data in an interim file, while another one downloads some additional data from the Internet

In an application that is running on the server, one thread, the listener thread, waits for a request from a

client As soon as the request comes in, the request is forwarded to a separate worker thread, which

continues the communication with the client The listener thread immediately comes back to get the next

request from the next client

With the Windows Task Manager, you can turn on the column Threads from the menu View Select

Columns and see the processes and the number of threads for every process Only cmd.exe is running

inside a single thread; all the other applications shown in Figure 19 - 1 use multiple threads You can see

one instance of Internet Explorer running 51 threads

Figure 19-1

A process contains resources, such as Window handles, handles to the file system, or other kernel objects

Every process has virtual memory allocated A process contains at least one thread The operating

system schedules threads A thread has a priority, a program counter for the program location where it

is actually processing, and a stack to store its local variables Every thread has its own stack, but the

memory for the program code and the heap are shared among all threads of a single process This makes

communication among threads of one process fast — the same virtual memory is addressed by all

threads of a process However, this also makes things difficult because multiple threads can change the

same memory location

Ngày đăng: 12/08/2014, 23:23

TỪ KHÓA LIÊN QUAN