- •Contents
- •What Is C#?
- •C# Versus Other Programming Languages
- •Preparing to Program
- •The Program Development Cycle
- •Your First C# Program
- •Types of C# Programs
- •Summary
- •Workshop
- •C# Applications
- •Basic Parts of a C# Application
- •Structure of a C# Application
- •Analysis of Listing 2.1
- •Object-Oriented Programming (OOP)
- •Displaying Basic Information
- •Summary
- •Workshop
- •Variables
- •Using Variables
- •Understanding Your Computer’s Memory
- •C# Data Types
- •Numeric Variable Types
- •Literals Versus Variables
- •Constants
- •Reference Types
- •Summary
- •Workshop
- •Types of Operators
- •Punctuators
- •The Basic Assignment Operator
- •Mathematical/Arithmetic Operators
- •Relational Operators
- •Logical Bitwise Operators
- •Type Operators
- •The sizeof Operator
- •The Conditional Operator
- •Understanding Operator Precedence
- •Converting Data Types
- •Understanding Operator Promotion
- •For Those Brave Enough
- •Summary
- •Workshop
- •Controlling Program Flow
- •Using Selection Statements
- •Using Iteration Statements
- •Using goto
- •Nesting Flow
- •Summary
- •Workshop
- •Introduction
- •Abstraction and Encapsulation
- •An Interactive Hello World! Program
- •Basic Elements of Hello.cs
- •A Few Fundamental Observations
- •Summary
- •Review Questions
- •Programming Exercises
- •Introduction
- •Essential Elements of SimpleCalculator.cs
- •A Closer Look at SimpleCalculator.cs
- •Simplifying Your Code with Methods
- •Summary
- •Review Questions
- •Programming Exercises
- •Introduction
- •Lexical Structure
- •Some Thoughts on Elevator Simulations
- •Concepts, Goals and Solutions in an Elevator Simulation Program: Collecting Valuable Statistics for Evaluating an Elevator System
- •A Deeper Analysis of SimpleElevatorSimulation.cs
- •Class Relationships and UML
- •Summary
- •Review Questions
- •Programming Exercises
- •The Hello Windows Forms Application
- •Creating and Using an Event Handler
- •Defining the Border Style of the Form
- •Adding a Menu
- •Adding a Menu Shortcut
- •Handling Events from Menus
- •Dialogs
- •Creating Dialogs
- •Using Controls
- •Data Binding Strategies
- •Data Binding Sources
- •Simple Binding
- •Simple Binding to a DataSet
- •Complex Binding of Controls to Data
- •Binding Controls to Databases Using ADO.NET
- •Creating a Database Viewer with Visual Studio and ADO.NET
- •Resources in .NET
- •Localization Nuts and Bolts
- •.NET Resource Management Classes
- •Creating Text Resources
- •Using Visual Studio.NET for Internationalization
- •Image Resources
- •Using Image Lists
- •Programmatic Access to Resources
- •Reading and Writing RESX XML Files
- •The Basic Principles of GDI+
- •The Graphics Object
- •Graphics Coordinates
- •Drawing Lines and Simple Shapes
- •Using Gradient Pens and Brushes
- •Textured Pens and Brushes
- •Tidying up Your Lines with Endcaps
- •Curves and Paths
- •The GraphicsPath Object
- •Clipping with Paths and Regions
- •Transformations
- •Alpha Blending
- •Alpha Blending of Images
- •Other Color Space Manipulations
- •Using the Properties and Property Attributes
- •Demonstration Application: FormPaint.exe
- •Why Use Web Services?
- •Implementing Your First Web Service
- •Testing the Web Service
- •Implementing the Web Service Client
- •Understanding How Web Services Work
- •Summary
- •Workshop
- •How Do Web References Work?
- •What Is UDDI?
- •Summary
- •Workshop
- •Passing Parameters and Web Services
- •Accessing Data with Web Services
- •Summary
- •Workshop
- •Managing State in Web Services
- •Dealing with Slow Services
- •Workshop
- •Creating New Threads
- •Synchronization
- •Summary
- •The String Class
- •The StringBuilder Class
- •String Formatting
- •Regular Expressions
- •Summary
- •Discovering Program Information
- •Dynamically Activating Code
- •Reflection.Emit
- •Summary
- •Simple Debugging
- •Conditional Debugging
- •Runtime Tracing
- •Making Assertions
- •Summary
Multi-Threading
CHAPTER 23
And here’s the output:
Hello from a single thread.
In Listing 23.1, an object of type SingleThread is instantiated within the Main() method. It contains the SayHello() method, which is executed as part of the thread in this program. All of the thread creation and initialization occurs in the following line:
Thread th = new Thread(new ThreadStart(st.SayHello));
The Thread object is declared as th. It’s instantiated as a new Thread object with a new ThreadStart delegate as its parameter. The delegate method handler for the
ThreadStart delegate is the SayHello() method of the SingleThread object, st.
Now the thread exists, but it’s idle, waiting for directions. It’s said to be in the unstarted state. To get this thread running, the program invokes the Start() method of the Thread object, th.
Synchronization
Using the techniques from Listing 23.1, it’s easy to create multiple threads of execution. As long as each thread minds its own business, the program runs fine. However, in many situations, this is not practical. It’s often necessary for multiple threads to share a resource. Without control, the behavior of multi-threaded programs sharing a resource yields non-deterministic results.
To provide that control, C# allocates methods to coordinate activities between threads. This coordination is properly termed synchronization. Correct implementation of synchronization enables programs to take advantage of performance benefits of multithreading as well as maintaining the integrity of object state and data.
This section uses the C# lock keyword to provide data synchronization. The code in Listing 23.2 shows how.
LISTING 23.2 Synchronized Data Access: Synchronization.cs
using System;
using System.Threading;
///<summary>
///Synchronized data.
///</summary>
class SyncData
{
int index = 0;
499
23
HREADINGT-ULTIM
500
Extreme C#
PART IV
LISTING 23.2 continued
string[] comment = new string[] |
||
{ “one”, |
“two”, “three”, |
“four”, “five”, |
“six”, |
“seven”, “eight”, |
“nine”, “ten” }; |
public string GetNextComment()
{
// allow only a single thread at a time lock (this)
{
if (index < comment.Length)
{
return comment[index++];
}
else
{
return “empty”;
}
}
}
}
///<summary>
///Demonstrates synchronized data access.
///</summary>
class Synchronization
{
SyncData sdat = new SyncData();
static void Main(string[] args)
{
Synchronization sync = new Synchronization();
Thread t1 = new Thread(new ThreadStart(sync.GetComments)); Thread t2 = new Thread(new ThreadStart(sync.GetComments)); Thread t3 = new Thread(new ThreadStart(sync.GetComments));
t1.Name = “Thread 1”; t2.Name = “Thread 2”; t3.Name = “Thread 3”;
t1.Start();
t2.Start();
t3.Start();
}
public void GetComments()
{
string comment;
Multi-Threading
CHAPTER 23
501
LISTING 23.2 continued
do
{
comment = sdat.GetNextComment();
Console.WriteLine(
“Current Thread: {0}, comment: {1}”, Thread.CurrentThread.Name, comment);
} while (comment != “empty”);
}
}
Here’s sample output from Listing 23.2:
Current Thread: Thread 1, comment: one
Current Thread: Thread 3, comment: two
Current Thread: Thread 2, comment: three
Current Thread: Thread 1, comment: four
Current Thread: Thread 1, comment: five
Current Thread: Thread 1, comment: six
Current Thread: Thread 1, comment: seven
Current Thread: Thread 1, comment: eight
Current Thread: Thread 1, comment: nine
Current Thread: Thread 1, comment: ten
Current Thread: Thread 1, comment: empty
Current Thread: Thread 3, comment: empty
Current Thread: Thread 2, comment: empty
There are three threads of execution in Listing 23.2 that obtain synchronized access to data. The construction of the threads in the Main() method of the Synchronization class is similar to how threads were created in Listing 23.1. To keep track of each thread, the program sets each thread’s Name property.
The GetComments() method of the Synchronization class is run by each thread. This method obtains a new piece of data, comment, from a SyncData object and prints its value to the console. The loop ends when the SyncData object returns the string empty.
The SyncData object provides synchronized access to its data. The only way to get to the data is through the public GetNextComment() method. Within this method is an if statement, keeping data reads from going beyond the bounds of the array. Until index reaches the end of the array, the next comment is returned and index is incremented so the next thread gets the next comment. When index reaches the end of the array, the method returns the string empty to signify that there is no more data to return.
23
HREADINGT-ULTIM
502
Extreme C#
PART IV
Surrounding the if statement in the GetNextComment() method is a lock statement. Here’s a cutout of the lock statement from Listing 23.2:
lock (this)
{
// statements
}
The parameter of the lock statement is this. The parameter for a lock statement can be any reference type expression. An invalid expression would be a value type, such as an int type. The lock statement implements mutual exclusion on the statements inside the curly braces.
Tip
Use the lock statement for mutually exclusive access to data in a multi-threaded program.
Without the lock statement, it would be possible for two or more threads to be reading the same value at the same time. In the absence of a lock statement, if the statements inside the curly braces represented an airline seat reservation or a bank account withdrawal, the results would not be nice. The lock statement ensures that only one thread at a time can be executing those statements.
Summary
This chapter presented multi-threaded applications in C#. The first section discussed how to create and start a thread, including declaring a thread argument and passing it a delegate with the method to be invoked, as well as executing the thread.
To keep threads from wreaking havoc with shared data, it’s often necessary to use synchronization objects. Proper thread synchronization helps manage access to program data. The example program in this chapter used lock statements, providing a mutual exclusion access scenario to program data.
Multi-threading is common on server programs that create new threads to handle client requests. The next chapter, “Browsing the Network Libraries,” shows how to create clients and servers that communicate over a network.
CHAPTER 25
String
Manipulation
IN THIS CHAPTER
• |
The String Class 516 |
|
• |
The StringBuilder Class 533 |
|
• |
String Formatting |
540 |
• |
Regular Expressions |
541 |