close

Se connecter

Se connecter avec OpenID

Advanced Language Concepts in C#

IntégréTéléchargement
Advanced Language Concepts in C#
Session 3
Last Update: 3/09
David Figge
dfigge@u.washington.edu
Page 1
Copyright (C) 2009 by David Figge. All Rights Reserved.
Where We’re at, Where We’re Going…
Advanced Language Concepts in C#
Last Update: 3/09
Page 2
Copyright (C) 2009 by David Figge. All Rights Reserved.
Class 3 Schedule






Session 1:

Review, Introductions

Language INtegrated Query (LINQ)
Session 2:

More Linq (continued)
Session 3:

Still More Linq (continued)
Session 4:

Creating tables in a Database

Attributes
Session 5:

Relationships and Referential
Integrity
Session 6:

Displaying XML data with DataGrid

Nullable Types

SQL Security Concepts

.Net Security
Last Update: 3/09




Page 3
Session 7:

Class Libraries

Namespaces and Assemblies

Versioning

Global Assembly Cache (GAC)

Extern Aliases
Session 8:

Multi-Threading
Session 9:

Anonymous Methods

Integrating Help

Localization

Windows Setup/Click-Once
Deployment
Session 10:

Final Project
Copyright (C) 2009 by David Figge. All Rights Reserved.
Working with Class Libraries,
Namespaces, and Assemblies
Advanced Language Concepts in C#
Last Update: 3/09
Page 4
Copyright (C) 2009 by David Figge. All Rights Reserved.
Assemblies

In .Net, a deployable unit of code is called an
Assembly



Typically, it consists of one module, created by
compiling one or more source files into an .exe or
.dll file
We’ve been building our Address program into a
single module assembly called address.exe
.Net does support multi-module assemblies

I’m not going to go into that here

Visual Studio doesn’t support it




So you’d have to use to command-line compiler with options
It’s not commonly needed
Instructions to do this are in the book
Let's see more about assemblies…
Last Update: 3/09
Page 5
Copyright (C) 2009 by David Figge. All Rights Reserved.
Assembly Characteristics

A binary file hosted by the CLR


Typically has either an .exe or a .dll extension


But can also have other extensions
Establish a type boundary


Although they use the standard executable file
format for Windows, it loads the CLR first, then
passes to the CLR the assembly start point
So if two assemblies define the same type, each is
seen as unique to its assembly
Support version numbers


The format is <major>.<minor>.<build>.<revision>
Along with an optional public key (“strongly
named”), this allows multiple versions of the
same assembly to coexist on the machine

Last Update: 3/09
More on this later
Page 6
Copyright (C) 2009 by David Figge. All Rights Reserved.
Assembly Characteristics

Self Describing

This means two things

All assemblies used by this one are specifically
referenced so they can be loaded as the program starts


The assembly has metadata describing the functions in
it


Although you can manually load assemblies at runtime
outside of this
You can access this information through the Reflection API
Configurable

Can be deployed as private or shared


More on this later
Config files can also be used to define locations
and loading options
Last Update: 3/09
Page 7
Copyright (C) 2009 by David Figge. All Rights Reserved.
Namespaces


When projects get large or use multiple
assemblies, the potential for naming
conflicts increases
To help manage these conflicts,
Namespaces are used to identify groups
of classes that go together


Namespaces are defined using the
Namespace keyword


Typically, by the source file or assembly
they're in
You can define new namespaces at any time
you see a value
Let's see an example of Namespaces…
Last Update: 3/09
Page 8
Copyright (C) 2009 by David Figge. All Rights Reserved.
Example Namespace
namespace
{
class
class
class
}
MyShapes
Circle { ... }
Triangle { ... }
Square { ... }
So here we have an example of the
Note namespace
the alternative
to including
the
MyShapes
defined
in, say, an
To use
the namespace
in our
using
statement
would be
to fully
add-on
DLL.
application,
we simply
put
a using
reference
Circle,
like
// Using the namespace (separate program...)
statement (you may need to add a
using System;
reference
theMyShapes.Circle();
namespace is in
Circle c = if
new
using MyShapes;
another assembly).
namespace MyApp
{
Using a fully qualified path can avoid
class MyAppClass {
namespace clashes
static void Main(string[] args)
{
Circle c = new Circle(); // Or = new MyShapes.Circle()
Square s = new Square(); // fully qualified can avoid
Triangle t = new Triangle(); // namespace clashes
}
}
}
Last Update: 3/09
Making sense
so far?
Page 9
Copyright (C) 2009 by David Figge. All Rights Reserved.
Aliases

C# also supports the use of aliases


These can come in handy when you have
two namespaces that have similar
functionality
Let's look at an example…
Last Update: 3/09
Page 10
Copyright (C) 2009 by David Figge. All Rights Reserved.
Alias Example
Sue, who works has a product
// In Bob.dll, namespace Bob, who works in the CoolVisuals
product division
at BigCorp
AlsoCoolVisuals,
published
by
namespace Graphics
SmallShop.
Sue’s
Triangle
function
is
{
So now we’re ready
to use Bob’s
circle
and Sue’s
Triangle.
class Circle { ... }
// Bob’s Circle function is really fast
than Bob’s.
But
there’s a problem.much
Sincebetter
we included
both using
class Triangle { ... }
class Square { ... }
statements, there are now two circle and two triangle
}
// In Sue.dll, namespace Sue. Sue
works at(not
SmallShop
in competition
with BigCorp
and Bob
functions
to mention
the squares!).
We could
fully
namespace Graphics
qualify all our uses, but that would be awkward…
{
So Bob, who works for the
class Circle { ... }
class Triangle { ... } // But Sue’s triangle function
beats group
Bob’s every
time
CoolVisuals
at BigCorp
has a set
class Square { ... }
Circle c = new BigCorp.CoolVisuals.Bob.Graphics.Circle()
of graphics functions. They aren’t
}
spectacular, except for his Circle
// separate program...
using System;
function, which is really fast.
using BigCorp.CoolVisuals.Bob.Graphics;
using SmallShop.AlsoCoolVisuals.Sue.Graphics;
namespace MyApp
{
class MyAppClass {
static void Main(string[] args)
{
Circle c = new Circle();
// Ambiguous. C# doesn’t know which you mean!
Triangle t = new Triangle();
}
}
}
This is where aliases come in…
Last Update: 3/09
Page 11
Copyright (C) 2009 by David Figge. All Rights Reserved.
Alias Example
// In Bob.dll, namespace Bob, who works in the CoolVisuals product division at BigCorp
namespace Graphics
{
class Circle { ... }
// Bob’s Circle function is really fast
class Triangle { ... }
class Square { ... }
}
// In Sue.dll, namespace Sue. Sue works at SmallShop in competition with BigCorp and Bob
namespace Graphics
{
class Circle { ... }
class Triangle { ... } // But Sue’s triangle function beats Bob’s every time
class Square { ... }
}
This is the syntax for an Alias. It allows
you to define an identifier that is a
placeholder for a namespace.
// separate program...
using System;
using bobs = BigCorp.CoolVisuals.Bob.Graphics;
using sues = SmallShop.AlsoCoolVisuals.Sue.Graphics;
namespace MyApp
{
class MyAppClass {
static void Main(string[] args)
{
Circle c = new bobs.Circle(); // Uses Bob.Graphics
Triangle t = new sues.Triangle(); // Uses Sue.Graphics
}
}
}
By using the alias, the
namespaces are clear, and
the code is easy to read.
Last Update: 3/09
Page 12
Questions
on that?
Copyright (C) 2009 by David Figge. All Rights Reserved.
Namespaces


You can also nest namespaces
By default, VS creates a namespace for
your app


Same as the name of your app
Change this using the Default Namespace
setting in the Application tab of the
project properties.
Last Update: 3/09
Page 13
Copyright (C) 2009 by David Figge. All Rights Reserved.
Applications vs. Class Libraries

An application consists of

A collection of functions



Resources (memory, etc)
An execution context (a “thread”)




This includes a stack
A class library (aka code library) consists of


One of which must be Main
A collection of functions
Resources (optional)
So a class library is simply a collection of
functions available to other programs
It uses the calling program’s context for
execution

i.e. its memory space, its “thread space”, etc
Last Update: 3/09
Page 14
Copyright (C) 2009 by David Figge. All Rights Reserved.
Let’s Try It…


Open up your Address program
Create a new project (part of the
solution)

Type is a Class Library



So you'll be able to use this for other apps as
well
Call it IUtils, for Internet Utilities
In it, put this code…
Last Update: 3/09
Page 15
Copyright (C) 2009 by David Figge. All Rights Reserved.
Locate Function
namespace IUtils
{
public class Maps
{
public static void Lookup(string address, string csz)
{
string combined = address + ", " + csz;
// Add+CSZ
string converted = combined.Replace(' ', '+'); // repl sp with +
string args = "maps.google.com/maps?q=" + converted;// Full URL
// Fire off IE as a new process
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = "iexplore.exe";
proc.StartInfo.Arguments = args;
proc.StartInfo.UseShellExecute = true;
proc.Start();
}
}
}
Last Update: 3/09
Page 16
Copyright (C) 2009 by David Figge. All Rights Reserved.
Using IUtils from Address



Make sure IUtils builds
Add a reference to IUtils from Address
Add a new button to the Address form



Call it btnMap
In it, we will call the Map.Locate function
in IUtils
Here’s the code…
Last Update: 3/09
Page 17
Copyright (C) 2009 by David Figge. All Rights Reserved.
Calling the Locate Function
private void btnMap_Click(object sender, EventArgs e)
{
Entry ent = SelectedEntries[current];
IUtils.Maps.Lookup(ent.Address, ent.CSZ);
}
Last Update: 3/09
Page 18
Type it in. It should work…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Private Assemblies

The IUtils DLL is a private assembly

It’s required to be in the same directory as the exe


You can dynamically load it (i.e. as it is running) from any
location
You can also use another location using a config file (in this
case, IUtils.config) to specify location





You can see it there now
By defining a reference to it, the DLL gets placed in
there
.Net does not use the registry when searching for
DLLs
Copying to another location is easy (unlike COM)


the book has more on this
copy all files in the directory
Private assemblies don’t specifically use version
numbers, as this is the only app that uses the DLL
where it is
Last Update: 3/09
Page 19
Copyright (C) 2009 by David Figge. All Rights Reserved.
Shared Assemblies


Like private assemblies, shared
assemblies contain functions and
(optionally) data that programs can
use
Shared assemblies, however, are
available to all .Net apps that want to
use them.


The .Net framework assemblies are, for
example, shared assemblies
So, what has to happen to make a
shared assembly?
Last Update: 3/09
Page 20
Copyright (C) 2009 by David Figge. All Rights Reserved.
Shared Assemblies

Shared Assemblies are placed in a
commonly accessible location on your
machine called the Global Assembly
Cache, or the GAC



Located at \windows\assembly
Note that only *.dll assemblies can be stored
in the GAC (not even *.exe)
Shared assemblies must have Strong
Names


This uniquely identifies the publisher of the
assembly
This could be a developer, a department, or a
company as a whole
Last Update: 3/09
Page 21
Copyright (C) 2009 by David Figge. All Rights Reserved.
Strong Names

The strong name creates a unique identifier for the
assembly



Similar to the GUID for COM objects
Strong names make use of public key/private key
encryption
Formally, they consist of

The friendly name of the assembly


The version number of the assembly



Also defined in the Build properties via VS
An optional culture identity value for localization
An embedded digital signature


Defined in the Build properties via VS
The public key value


The name of the assembly minus the extension
A combination of a hash of the assembly’s contents and the
private key value
Let’s apply a strong name to our IUtils DLL…
Last Update: 3/09
Page 22
Copyright (C) 2009 by David Figge. All Rights Reserved.
Strong Names

In Project Properties / Signing


Select Sign the assembly
Under Choose a Strong Name Key File




Select <New…>
Enter a name (IUtils) and a password of your
choice
That's it. You're good.
Rebuild it and copy it to the GAC


Last Update: 3/09
Easiest way is to drag into the GAC
Copy/Paste won't work…
Page 23
Copyright (C) 2009 by David Figge. All Rights Reserved.
Strong Names


Note that strong names also provide
some protection against tampering
Generally, it’s a good idea to strongly
name every assembly intended for
public consumption (even if private)
Last Update: 3/09
Page 24
Copyright (C) 2009 by David Figge. All Rights Reserved.
Extern Alias


An extern alias is used to reference to assemblies
with the same fully qualified type name but
different version numbers
To reference two assemblies with the same fullyqualified type names, an alias must be specified
on the compiler command line, like this:



/r:GridV1=grid.dll
/r:GridV2=grid20.dll
This creates the external aliases GridV1 and
GridV2. To use these aliases from within a
program, reference them using the extern
keyword. For example:


extern alias GridV1;
extern alias GridV2;
Last Update: 3/09
Page 25
Copyright (C) 2009 by David Figge. All Rights Reserved.
A Chance to Play


In this exercise you will build an
additional DLL assembly and use it from
the Address program
The DLL will have one function, called
CopyToClipboard


It is a utility that will copy any number of
strings to the system clipboard for pasting
into other apps. In our case, it will be the
entry currently displayed on the window
The DLL you create will be a shared
assembly (so others can use it too )
Last Update: 3/09
Page 26
Copyright (C) 2009 by David Figge. All Rights Reserved.
The AddressUtils DLL


Create the AddressUtils DLL as an additional project in your
solution
Add a reference to System.Windows.Forms


So you can access the clipboard
In it, create a ClipboardUtils class, with CopyToClipboard in it

public static void CopyToClipboard(params string[] p)





From your address program


Call this function copying the Name, Address, and CSZ to the clipboard
When it’s working, make the DLL a shared DLL by



p is an array of strings passed by the caller
Create one big long string consisting of each string in p followed by “\r\n” (each
one)
Call Clipboard.Clear() to erase current clipboard contents
Call Clipboard.SetText() to set the new contents to your string
Signing it
Placing it in the GAC
Good Luck!
30 Minutes
Last Update: 3/09
Page 27
Copyright (C) 2009 by David Figge. All Rights Reserved.
Working with Threads
Advanced Language Concepts in C#
Last Update: 3/09
Page 28
Copyright (C) 2009 by David Figge. All Rights Reserved.
Threads

What are threads?


A thread is a “line of execution” within a process
Why are they used?

To perform lengthy processes in the background


To wait for external event


For example, to update a clock on the display
To perform a task but keep Windows form responsive


For example, waiting for device to become ready
To perform long-term background tasks


For example, loading a large image
For example, sending a file across the network
When should I consider using threads in my program?



If the user interface responsiveness becomes too slow
When task can easily execute in background (and is
somewhat autonomous, like printing a file)
When it makes sense organizationally (for example, two
tasks that don’t interact and can be done simultaneously)
Last Update: 3/09
Page 29
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Basics

In Windows, a thread is always contained in a
Process
process



The process “owns” the address
space and system resources for
a program
So all threads within a process
have access to the same memory,
variables, functions, etc.
Memory
Files
Ports
Thread 1
Thread 2
In a single processor machine


Only one thread is actually running at a time
Periodically (every 20 ms or so) the Windows
OS stops the current thread and swaps it out
for another thread that’s ready to run


This is called a Timeslice or Quantum
On a dual CPU system, 2 threads are run
at a time (one for each CPU)
Last Update: 3/09
Page 30
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Basics

Thread States

Threads are always in one of several
states. The most significant states are



Ready (waiting for its turn on the CPU)
Running (only one per CPU is in this state)
Waiting on outside event


Last Update: 3/09
For example, file I/O.
When this event happens, an interrupt occurs. At
that point, data is placed into its destination buffer,
and the waiting thread is moved to the Ready state
Page 31
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Basics

Threads and Scheduling


Windows schedules threads (not processes)
Threads have priority


Numbered 0-32. Above 16 is called ‘realtime’
Threads with higher priority are always run if
ready (that’s how the scheduler works)


Normal is about 8. Multimedia runs at about 27.


Last Update: 3/09
So, if my thread is higher priority than yours, yours will
stop until my thread is complete, then yours runs again
By default, the thread inherits the priority of the
process creating it.
You can change your thread’s priority, but you typically
leave it alone unless there’s good reason to change it
Page 32
Copyright (C) 2009 by David Figge. All Rights Reserved.
Threads

How do I create threads?


Threads are supported in the
System.Threading namespace
You create a thread by

Creating an instance of the Thread class



Calling the Start() method



You pass in the function to execute
This just creates the object, it’s not going yet
This executes the thread
It may not run until your timeslice is complete
Let’s create a simple console app to play
with threading…
Last Update: 3/09
Page 33
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu",
"San Francisco", "Miami", "Cleveland" };
static void Main(string[] args)
{
Destination();
}
static void Destination()
{
Random r = new Random();
for (int x = 0; x < 25; x++)
{
int y = r.Next() % 4;
// Choose a random city
Console.WriteLine(destinations[y]); // Display it
}
}
Last Update: 3/09
Page 34
Type it in, then we’ll look at it. It should work…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination

So this gives us a reasonable way to
choose which city we should use for
our next vacation


Mostly, it gives us something to play with
using threads 
So, if one call to the destination
function is good, four must be even
better, right?

Let’s modify this so that we run 4
concurrent threads calculating our
destination…
Last Update: 3/09
Page 35
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu" ...,
static void Main(string[] args)
{
Thread[] t = new Thread[4];
// uses System.Threading
for (int x = 0; x < 4; x++) {
t[x] = new Thread(Destination);
t[x].Name = "Thread" + x;
So, as you see, we create
t[x].Start();
an array of 4 Threads.
}
}
For each one, we create the Thread
Threads
have
several useful
static void Destination()
Threads are not
actually
started
object
by passing
the name of the
properties
associated
with them.
{
until you call the
Start
function.
At
function associated with the
Random r = new Random();
Here
we’re
the Name
that point, thethread.
thread
will using
be
Like
Main, when that
for (int x = 0; xplaced
< 25;inx++)
property,
so we
can tell each of
the queue
for the
next
function
ends,
the thread
{
them
apart
from
one
available timeslice.terminates. another.
int y = r.Next() % 4;
Console.WriteLine(Thread.CurrentThread.Name + ": " + destinations[y]);
}
}
Everyone have it working?
Making sense?
Last Update: 3/09
Page 36
Once again, type it in, then we’ll talk…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination


So we now have 4 threads executing
the same function simultaneously
Remember, to create a thread


Create the object, passing the name of the
thread function to the constructor
Call the .Start() method of the new thread
object


It will not start until you do this
You can also pass a parameter to the
thread function. Let’s see how that’s
different…
Last Update: 3/09
Page 37
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu" ...,
static void Main(string[] args)
{
So, as you can see, we’re simply
Thread[] t = new Thread[4];
// uses System.Threading
passing the name of the thread as
for (int x = 0; x < 4; x++) {
a parameter. Any object can be
t[x] = new Thread(Destination);
passed as the parameter (so, for
// t[x].Name = "Thread" + x;
example, an array of settings)
t[x].Start("Thread " + x);
}
}
static void Destination(object name)
{
string MyName = (string)name;
Random r = new Random();
for (int x = 0; x < 25; x++)
{
int y = r.Next() % 4;
Console.WriteLine(MyName + ": " + destinations[y]);
}
Questions
}
on this?
Last Update: 3/09
Page 38
Go ahead and get these changes in…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread.Sleep()

The Sleep function is used to cause the current thread to
stop executing for a specific number of milliseconds.


For example, Thread.Sleep(100)
The milliseconds is approximate.



This can be useful when you’re waiting for something to
occur, and simply need to check it periodically to see if it
is ready
It can also be useful when something is timed



You will not return for at least 100 ms, but may be longer than
that
For example, counting down seconds. You can update the
time then sleep for 1 second (1000 ms)
You can also use timers for these if needing it for an
extended time or often
Let’s add a Sleep in our code to make sure someone else
gets a chance after we’ve printed our destination

This should stop multiple prints from the same thread
Last Update: 3/09
Page 39
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static void Destination(object name)
{
string MyName = (string)name;
Random r = new Random();
for (int x = 0; x < 25; x++)
{
int y = r.Next() % 4;
Console.WriteLine(MyName + ": " + destinations[y]);
Thread.Sleep(5);
}
}
Okay, so let’s put in another change
and see what happens…
Is this making sense?
Last Update: 3/09
Page 40
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu" ...,
static StringBuilder dest = new StringBuilder();
static void Main(string[] args)
{
...
}
static void Destination(object name)
{
string MyName = (string)name;
Random r = new Random();
for (int x = 0; x < 25; x++)
{
int y = r.Next() % 4;
dest.Length = 0;
// Start new word
for (int z = 0; z < destinations[y].Length; z++)
{
dest.Append(destinations[y][z]);
// Copy destination to dest
Thread.Sleep(1);
// Pause a little
}
Console.WriteLine(MyName + ": " + dest); // Write destination out
Thread.Sleep(5);
}
}
Last Update: 3/09
Page 41
Put this in and see what happens…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination


So what happened?!?
The dest variable is an example of a shared resource


What we saw was an example of Collision



They act as bottle-necks to the program
In our case, simply making dest a local (non-static) variable would
solve that
What are some real-world examples of shared resources?


Where two threads USED the same resource at the same time
Generally, you want to avoid having shared resources


An element of the program that is (potentially) used by more than
one thread at a time
I thought of: An airplane bathroom, public bathrooms in general
(a limited number of resources, even if more than one),
telephones, cars, televisions…
What are some computer examples of shared resources


I thought of: print spoolers, shared output files, network
communications (pipes), the console output screen, databases!
Anything that has only one access point and isn’t built to support
multiple threads communicating through it simultaneously
Last Update: 3/09
Page 42
Copyright (C) 2009 by David Figge. All Rights Reserved.
Avoiding Collisions

Collisions are worth avoiding



How do we avoid collisions on an airplane
bathroom?
A C# lock is used in the same way




You ask for a resource
If it’s available, you lock it, use it, unlock it
If it’s unavailable, you wait until whoever has it
unlocks it (releases the lock)
All objects in C# can be used in a lock


They can corrupt data and can be very hard to
find
You just need to make sure everyone using the
same resource is using the same lock object
Let’s see how that works…
Last Update: 3/09
Page 43
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu" ...,
static StringBuilder dest = new StringBuilder();
static void Main(string[] args)
{
So only one thread can get into
...
this code at a time. If someone
}
static void Destination(object name)else has dest locked, you must
{
wait for it to be released. When
string MyName = (string)name;
it’s released,
a madofscramble
This section
code is
Random r = new Random();
happens referred
to determine
gets to
for (int x = 0; x < 25; x++)
to as who
a Critical
{
be theSection,
next thread.
Theit’s
operating
because
limited
int y = r.Next() % 4;
system
that
only
one
toensures
oneApply
thread
at
a time.
lock(dest)
//
lock
via dest
thread gets in at a time.
{
dest.Length = 0;
for (int z = 0; z < destinations[y].Length; z++)
{
dest.Append(destinations[y][z]);
Thread.Sleep(1);
The lock is released at the
}
end
block.
Console.WriteLine(MyName
+ of
":the
" code
+ dest);
}
// Release the lock
Still making sense?
Thread.Sleep(5);
}
}
Add this, then we’ll talk…
Last Update: 3/09
Page 44
Copyright (C) 2009 by David Figge. All Rights Reserved.
Deadlock


An important concern anytime you’re using shared
resources/locks is deadlock (“Deadly Embrace”)
An example of deadlock situation might be the following



Thread 1 needs to update files A,B, and C
Thread 2 needs to update F, and C, and B
To begin



And now




Thread 1 Starts the process by locking files A and B for update
Thread 2 also starts and locks F and C
At this point, thread 1 tries to lock C, but thread 2 has it.
Meanwhile thread 2 is waiting for file A to be released, but thread
1 has it
Both threads are waiting for resources the other has, and aren’t
planning on giving them up until they’re done
You now have a deadlock situation in which the program
hangs.
Last Update: 3/09
Page 45
Copyright (C) 2009 by David Figge. All Rights Reserved.
Deadlock

The two key elements to deadlock
avoidance are


Be aware that it happens. Look for
situations where this may occur. If you
can, avoid them
If you can’t, set up a timeout situation

If thread 1 is waiting for a file lock for, say,
more than 500ms




Last Update: 3/09
Stop. Release all the locks it currently has.
Wait a random (short) time
Reacquire the locks
If all your threads do this, you can avoid
deadlock situations
Page 46
Copyright (C) 2009 by David Figge. All Rights Reserved.
Background Threads

We’ve been dealing with Foreground
Threads


The more common thread is a
Background Thread



These are critical to the program and the
program does not end until these threads do
This thread runs normally, but if the program
is exited, the thread is killed
In Windows, you generally want your threads
to be background threads
Let’s make our threads background
threads
Last Update: 3/09
Page 47
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu" ...,
static void Main(string[] args)
{
Thread[] t = new Thread[4];
// uses System.Threading
for (int x = 0; x < 4; x++) {
t[x] = new Thread(Destination);
t[x].IsBackground = true;
// Mark threads as background
t[x].Start("Thread " + x);
}
}
Last Update: 3/09
Page 48
Copyright (C) 2009 by David Figge. All Rights Reserved.
Background Threads

What happened?



By making the “Destination” threads
background threads, we said, “If the
program ends, kill these threads”
The main program ended when Main was
done executing
You can suspend the current thread
until another thread completes by the
Join() method…
Last Update: 3/09
Page 49
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Example: Destination
static string[] destinations = { "Honolulu" ...,
static void Main(string[] args)
{
Thread[] t = new Thread[4];
// uses System.Threading
for (int x = 0; x < 4; x++) {
t[x] = new Thread(Destination);
t[x].IsBackground = true;
t[x].Start("Thread " + x);
}
t[0].Join();
// Wait for threads to complete
t[1].Join();
t[2].Join();
t[3].Join();
}
Last Update: 3/09
Page 50
Copyright (C) 2009 by David Figge. All Rights Reserved.
Race Conditions



In addition to deadlocks, you also need to
keep an eye out for race conditions
A race condition is where one thread assumes
a second thread has completed enough of its
work for the first thread to go forward
An example


Thread 1’s job is to open a file
In the meantime, thread 2 is processing the
information that’s going to go in the file


Since this takes about 2 seconds, thread 1 should be
easily finished when this is done, so thread 2 just writes
the data to the file thread 1 just opened.
But, what if thread 1 was delayed opening the
file (maybe another process had it locked…)

Last Update: 3/09
In this case, thread 2 would try to write data to a closed
file (and fail, obviously)
Page 51
Copyright (C) 2009 by David Figge. All Rights Reserved.
Race Conditions

You can easily avoid race conditions with two
steps


Be aware that it happens. Look for situations
where this may occur. If you can, avoid them.
If you can’t, simply have a flag that thread 1 sets
when the file is opened.




Thread 2 then makes sure that the flag is set before
continuing with the writing
If it isn’t set, either wait (sleeping is best) for it to be set
or throw an exception
You can also use Events (AutoResetEvent and
ManualResetEvent)
Technically, our previous problem was in our
program was a race condition

Our main thread ‘assumed’ the other threads had
completed and exited the program
Last Update: 3/09
Page 52
Copyright (C) 2009 by David Figge. All Rights Reserved.
Background Threads

When a C# application starts, it is given one
thread



This thread is intended for use by the UI, and not for
significant background processes
If you use this thread for lengthy operations, it will
appear to hang the UI
If this happens, the first step is to set the form’s cursor
to the hourglass


The next step would be to use a background thread
to perform the operation




But this still causes the UI to hang, so don’t do this too long
Ideally, the main program could continue
But even if the main program has to wait, at least you
could have a cancel button to abort
Printing is an obvious example
However, you run into a problem…
Last Update: 3/09
Page 53
Copyright (C) 2009 by David Figge. All Rights Reserved.
The UI Problem


Say, for example, you have a print option
that displays its progress to a ProgressBar
control
Simple, right…


Create the form and display it
Start the printing thread



As the print thread progresses, have it update its
progress on the progress bar control
When it’s done, it closes the “printing” form
Unfortunately, it’s not quite that simple

For one thing, only the thread that created
the control can access it

Last Update: 3/09
This is because controls aren’t designed to be
accessed by multiple threads at the same time
Page 54
Copyright (C) 2009 by David Figge. All Rights Reserved.
The BackgroundWorker


The solution to this is a thread class
specifically designed for background
tasks called the BackgroundWorker
Among other things, it let’s you




Specify the function that does the work
Specify a function that updates progress
Specify a function to cancel the operation
Specify a function to call when the job’s
done
Last Update: 3/09
Page 55
Copyright (C) 2009 by David Figge. All Rights Reserved.
Class Exercise

Going back to our Address program, let’s
add a “Print” button that uses the
BackgroundWorker class to simulate
printing a record to the printer



In our case, instead of actually printing,
we’re going to wait for 5 seconds
As we wait, we’ll display a progress bar
If you wish, you can swap this code later for
code that actually prints

Last Update: 3/09
But this also gave us the opportunity to look at
progress bars 
Page 56
Copyright (C) 2009 by David Figge. All Rights Reserved.
Printing: Step 1 – the Print Form

Create a form like this:




Call in frmPrint
Button: btnCancel
Progress Bar: pBar
Proper OOP design says that the form
should be in charge of its own controls,
so add these functions to the frmPrint
code…
Last Update: 3/09
Page 57
Copyright (C) 2009 by David Figge. All Rights Reserved.
Print Form Code
BackgroundWorker WorkerThread;
// The ‘printing’ thread
public frmPrint(BackgroundWorker thread)
{
UpdateProgress is used to
WorkerThread = thread; update the progress
//theSave
so we the
could
If
user
bar.
presses
Cancelcancel
InitializeComponent(); That’s done
button,
simplywebyneed to signal to the
}
setting the .Value
BackgroundWorker
property
thread that it
of theneeds
bar. to abort. We do that by
calling its CancelAsync method. Of
public void UpdateProgress(int amt)
to dothe
that, we need access
{
Socourse,
we modify
to the
thread
constructor
toProgress
take the so far
pBar.Value = amt;
//BackgroundWorker
object…
BackgroundWorker
}
thread object, and store
it into a class variable.
// Add this function by double-clicking
the cancel button
private void btnCancel_Click(object sender, EventArgs e)
{
WorkerThread.CancelAsync();
// Cancel printing
}
Is this making sense
so far?
Last Update: 3/09
Page 58
As usual, type, then talk. It won’t work for a while…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Printing: Step 2 – the Print Button


Add a button to your main Address Book
form called btnPrint. Double-click it to
create the btnPrint_Click method
In this method we’ll


Create the BackgroundWorker thread
Point its delegates to functions that






Do the work (simulate printing)
Update the progress bar
Complete the printing
Create the frmPrint form
Start the ‘printing’ process
Display the frmPrint form with ShowDialog
Last Update: 3/09
Page 59
Copyright (C) 2009 by David Figge. All Rights Reserved.
btnPrint Code
So the BackgroundWorker class has several
delegates that point to functions used. Here
thoseClass
delegates
to point to our
frmPrint printform = null; we set//up New
Variable
functions.sender,
Questions EventArgs
on that part? e)
private void btnPrint_Click(object
Next we set some flags
{
to show what
BackgroundWorker printthread = new BackgroundWorker();
capabilities we’re
printthread.DoWork += Print;
supporting (report
Next we create the
printthread.ProgressChanged += PrintProgress;
progress
and
Before
wecancel).
displaypassing
the
frmPrint
object,
printthread.RunWorkerCompleted += PrintCompleted;
form,
need to start the
thewe
BackgroundWorker
printthread.WorkerReportsProgress =Now
true;
we display
the
printing.
This
thread
(soisit(ultimately)
can cancel)
dialog
box.
When
printthread.WorkerSupportsCancellation
= the
true;
calling
.Startitmethod
comes back,
printing
is
on the
thread.
either completed
or wasform
printform = new frmPrint(printthread);
// Create
printthread.RunWorkerAsync(); // Callcancelled.
DoWork()
// Display form, if cancelled say so
if (printform.ShowDialog() == DialogResult.Cancel)
MessageBox.Show("Printing Aborted");
}
Questions on
this code?
Last Update: 3/09
Page 60
Type this in. It still won’t work, but we’re closer…
Copyright (C) 2009 by David Figge. All Rights Reserved.
The PrintProgress Function

The PrintProgress function’s purpose is to
update the Progress Bar to the current
state of the “printing”


Progress default to counting from 0 to
100 (i.e. percent)



Note that this function is called in the context
of the UI thread, so it can update the control
without throwing an exception
We’ll call this function every 5 percent of the
way through the ‘printing’
This function will simply pass this on to
the printform’s UpdateProgress function
Here’s the code…
Last Update: 3/09
Page 61
Copyright (C) 2009 by David Figge. All Rights Reserved.
The PrintProgress Function
private void PrintProgress(object sender, ProgressChangedEventArgs e)
{
printform.UpdateProgress(e.ProgressPercentage);
}
This is accessed through the
ProgressChanged delegate of the
BackgroundWorker. When we call that
delegate, we specify what progress we’ve
made, which is placed into the
ProgressPercentage variable. We’ll cover
that shortly.
Last Update: 3/09
Page 62
Get this typed in first, then we’ll cover it…
Copyright (C) 2009 by David Figge. All Rights Reserved.
The PrintCompleted Function

The PrintCompleted function is called
in one of two circumstances





Both indicate that the process is done
First: print finished normally
Second: printing was aborted
So our code will tell the Print form to
return either DialogResult.OK or
DialogResult.Cancel based on if it was
cancelled or not
Here’s that code…
Last Update: 3/09
Page 63
Copyright (C) 2009 by David Figge. All Rights Reserved.
The PrintCompleted Function
private void PrintCompleted(object sender, RunWorkerCompletedEventArgs e)
{
printform.DialogResult=e.Cancelled ? DialogResult.Cancel : DialogResult.OK;
printform.Close();
}
This is called automatically when the
Thread’s function ends. We set the
DialogResult property of the frmPrint to
indicate whether we ended by
completion or cancelation. Then we close
the dialog box (returning to the btnPrint
function).
Last Update: 3/09
Page 64
Type, then talk…
Copyright (C) 2009 by David Figge. All Rights Reserved.
The Print Function


Finally we’re ready for the Print function
itself
Remember its purpose is to



Run for about 5 seconds
Update the progress bar every 5%
Cancel the process if the cancel button was
pressed





The button press called AsyncCancel
Which sets the CancellationPending flag of the
DoWorkEventArgs argument
So we’ll check that
End when we’ve done 100% of the work
Here’s the code…
Last Update: 3/09
Page 65
Copyright (C) 2009 by David Figge. All Rights Reserved.
The Print Function
Within
our loop, we first see
public void Print(object sender,
DoWorkEventArgs
e)if we’ve
been asked to cancel. If so, we set the
{
cancel flag to true and exit the function
BackgroundWorker thread = (BackgroundWorker)sender;
(which calls the PrintCompleted function
int currentpct = 0;
automatically)
do
start by taking
{
Otherwise, weWe
report
sendercalls
(which is the
our progress (which
if (thread.CancellationPending)
BackgroundWorker) and
our PrintProgress
{
We simulate
printing
saving
it so we can use it
function,
which
updates
e.Cancel = true;
activity
by sleeping
forlater.
a
progress
And
keep
it our
upbar).
until
theChange
progress
return;
second…
status…
we’re¼done
(at which
}
point we exit, and
thread.ReportProgress(currentpct);
PrintCompleted is called
Thread.Sleep(250);
automatically)
currentpct += 5;
} while (currentpct <= 100);
}
There’s a lot here. Any
questions on this?
Last Update: 3/09
Page 66
The final code. Type it in, it should work…
Copyright (C) 2009 by David Figge. All Rights Reserved.
Thread Summary

Threads are worth considering when




Create a thread via the Thread class




Pass the function to execute
Call the Start() method to begin the thread
Call the Join() function to wait for it to end
Be aware of




Working in foreground thread is too long
When task is somewhat stand-alone and can easily execute
in background
It makes sense organizationally
Collisions (use locks to avoid this)
Deadlock (use timeouts to avoid this)
Race conditions (use flags to avoid this)
The BackgroundWorker class is convenient


Allows easy creation of background tasks
Supports UI updates on progress and easy cancellation
Any questions
on threads?
Last Update: 3/09
Page 67
Copyright (C) 2009 by David Figge. All Rights Reserved.
End of Session 3
Advanced Language Concepts in C#
Last Update: 3/09
Page 68
Copyright (C) 2009 by David Figge. All Rights Reserved.
Auteur
Документ
Catégorie
Без категории
Affichages
4
Taille du fichier
2 910 Кб
Étiquettes
1/--Pages
signaler