Вы находитесь на странице: 1из 32

Threads

What is a Thread?
• A thread is a single sequential flow of control.
• A multithreaded program consists of multiple
threads.
• This means that at any instance of time the program
will have multiple points of execution one in each
thread.
• Threads execute in a single address space ( in
single process).
• Threads share static and instance variables.
• However each thread executes on its on call stack
with its own separate local variable.
Creating Threads
• A thread is created by
– creating an object of type
System.Threading.Thread
– by passing ThreadStart delegate to its
constructor.
– Note that Thread class is sealed.
• Calling start on the thread causes a thread to
execute the method assigned to the delegate.
• When the thread finishes executing it dies.
ThreadStart
• The signature of the delegate is
– public delegate void ThreadStart()
• Any method that is passed to this delegate must
match its signature.
• Which means method must return void and it
takes no parameters.
But what if I want to call parametetized methods?
Suppose I need to pass values to the method then….

We will deal with that …. But before that we will take a look
at an example
Some members of Thread
• Start()
– Causes the operating system to change the state of the current
instance to ThreadState.Running.
• Thread(ThreadStart)
– Initializes a new instance of the Thread class.
• Sleep(Int32)
– Suspends the current thread for a specified time
• Interrupt()
– Interrupts a thread that is in the WaitSleepJoin thread state.
• CurrentThread
– Gets the currently running thread.
• IsAlive
– Gets a value indicating the execution status of the current thread.
• Name
– Gets or sets the name of the thread.
• ThreadState
– Gets a value containing the states of the current thread.
ThreadStates
Thread State Description
Unstarted Thread is Created within the
common language run time but not
Started still.
Running After a Thread calls Start method
WaitSleepJoin After a Thread calls its wait or Sleep
or Join method.
Suspended Thread Responds to a Suspend
method call.
Stopped The Thread is Stopped, either
normally or Aborted.
Example
using System;
using System.Threading;
class SimpleThread{
private int ind = 0;
public void CountUp(){
while (ind < 10) {
ind++;

Console.WriteLine(Thread.CurrentThread.Name + "
" + ind);
Thread.Sleep(1000);
}
}
public static void Main()
{
SimpleThread ex = new SimpleThread();
Thread t2 = new Thread(new
ThreadStart(ex.CountUp));
t2.Name = "t2"; On executing
Thread t3 = new Thread(new
t3 2
ThreadStart(ex.CountUp));
t2 1
t3.Name = "t3";
t2 3
t2.Start();
t3 4
t3.Start();
t2 5
}
t3 6
}
t2 7
t3 8
Note that you may get a different result.
t2 9
Can you guess WHY?
t3 10
Passing information to the thread
methods
• If some data needs to passed to thread then this
can be done in two
– Using delegate
ParameterizedThreadStart
• ParameterizedThreadStart requires
the method assigned to it take a
parameter of type object and return void.
– Using instance variables of the class in
which the delegate method is defined. This of
course is way to get around the problem
when any type and any number of argument
needs to available to the thread method.
Example
using System;
using System.Threading;
public class ParamClass{
public static void Main() {
Thread paramThread
= new Thread(POperation);
paramThread.Start("Test");
}
private static void POperation(object
o) {
Console.WriteLine(
"Param worker: {0}", o);
}
}
Some more members of Thread
• IsBackground
– Threads are by default a foreground thread. to
make it run as background (like deamon thread in
java) set t.IsBackground=true;
• Join()
– makes the calling thread wait until the given thread
terminates.
– public void Join();
– public bool Join(int);
– public bool Join(TimeSpan);
• Priority
– Values can be AboveNormal, BelowNormal,
Highest, Lowest, Normal
Example
using System;
using System.Threading;
public class JoinClass{ Comment this line and
public static void Main() { execute to see the result
Thread paramThread
= new Thread(POperation);
paramThread.Start("Test");
paramThread.Join();
Console.WriteLine("end of main");
}
private static void POperation(object o) {
Console.WriteLine("Param worker: {0}", o);
}}
On executing Param worker: Test
end of main
Thread Pool
• Thread pool is a collection of threads that can be used
to perform a number of tasks in the background.
• Once a thread in the pool completes its task, it is
returned to a queue of waiting threads, where it can be
reused.
• Note that all the thread pool threads are background
threads. You cannot change the pool thread to
foreground thread.
• This class uses entirely static methods –there
is a single pool of threads for the entire application
• They are mainly employed in server applications.
Example
using System;
using System.Threading;
class ThreadPoolClass{
static void Main(){
int t1, t2;
ThreadPool.GetMaxThreads(out t1, out t2);
Console.WriteLine("Max worker threads="+ t1+
" I/O completed threads=" + t2);
for(int i=0;i<4;i++)
ThreadPool.QueueUserWorkItem(new
WaitCallback(Job));
Thread.Sleep(1000);
} Delegate WaitCallback
static void Job(object st){
for(int i=0;i<4;i++)
Console.WriteLine("loop "+ i + "thread
"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50);
Max worker threads=50 I/O completed
} threads=1000
} loop 0thread 3
loop 0thread 4
loop 1thread 4
loop 2thread 4
loop 1thread 3
loop 2thread 3
On executing loop 3thread 3
loop 3thread 4
loop 0thread 3
50 threads are possible in loop 1thread 3
the current settings. loop 2thread 3
loop 3thread 3
4 jobs are processed by loop 0thread 4
just two threads loop 1thread 4
loop 2thread 4
loop 3thread 4
Timer
• Threads can also be scheduled to execute at
certain time intervals. This is supported by the
Timer class in the .NET environment.
• The Timer class's constructor is used to create
a timer object. The constructor is overloaded.

Public Timer()
Public Timer(double)
– Sets the interval property to the specified.
Timer members
• Tick
– This event occurs when the Interval has elapsed.
• Start
– Starts raising the Tick event by setting Enabled to true.
• Stop
– Stops raising the Tick event by setting Enabled to false.
• Close
– Releases the resources used by the Timer.
• AutoReset
– Indicates whether the Timer raises the Tick event each
time the specified Interval has elapsed or whether the
Tick event is raised only once after the first interval has
elapsed.
• Interval
– Indicates the interval on which to raise the Tick event.
• Enabled
– Indicates whether the Timer raises the Tick event.
Example
using System;
using System.Windows.Forms;
using System.Drawing;

class TimerClass:Form{
Timer Clock;
Label lbTime=new Label();
public TimerClass() {
Clock=new Timer();
Clock.Interval=1000;
Clock.Start();
Clock.Tick+=new
EventHandler(Timer_Tick);
this.Controls.Add(lbTime);
lbTime.Text=GetTime();
}
public string GetTime() {
string TimeInString="";
int hour=DateTime.Now.Hour;
int min=DateTime.Now.Minute;
int sec=DateTime.Now.Second;

TimeInString=(hour < 10)?"0" +


hour.ToString() :hour.ToString();
TimeInString+=":" + ((min<10)?"0" +
min.ToString() :min.ToString());
TimeInString+=":" + ((sec<10)?"0" +
sec.ToString() :sec.ToString());
return TimeInString;
}
public void Timer_Tick(object
sender,EventArgs eArgs) {
if(sender==Clock) {
lbTime.Text=GetTime();
}
}

public static void Main() {


Application.Run(new TimerClass());
}
}
Synchronizing Threads
• When two or more threads run on the same
object’s method and share/modify the same
instance members then the state of the object
comes into question.
• Only one thread should be allowed to change
the state of an object at any time.
• This is where thread synchronization comes into
picture.
• The way synchronization can be achieved is
through object locking.
lock
• To lock an object
– lock(obj) {
// can safely make changes in the obj state
}
– lock (this){
// can safely make changes to the current object
state
}
• To lock static members
– lock (typeof(StaticClass))
• Lock costs time and may not be always needed.
• The example in the next slide shows how you can make
available two versions of an object depending on what
the ‘class-user’ wants.
using System;
Example
using System.Threading;

public class Account{


int balance=1000;
bool IsSynchronized = false;

public virtual void deposit(object a) {


Thread.Sleep(1000);
int amt = (int )a; balance += amt;
Console.WriteLine("balance after deposit is
" + balance);
}
public virtual void withdraw(object a) {
int amt = (int )a;
if(balance>amt) { Thread.Sleep(1000);
balance -= amt;
Console.WriteLine("balance after withdraw
is " + balance);}
else
Console.WriteLine("Amount not
available");
}

public static Account Synchronized(Account d)


{
if (!(d.IsSynchronized))
return new SyncAccount(d);
else return d;
}
private class SyncAccount : Account
{
private Account d;
public SyncAccount(Account d) {
IsSynchronized = true;
this.d = d;
}

public override void deposit(object a ) {


int amt = (int )a;
Thread.Sleep(1000);
lock (this) {
balance += amt;
Console.WriteLine("balance after deposit is "
+ balance);
}
} Creating an inner class that will give synchronized version
public override void withdraw(object a) {
int amt = (int )a;
lock (this) {
if(balance>amt) {
Thread.Sleep(1000);
balance -= amt;
Console.WriteLine("balance after withdraw is
" + balance);
}
else
Console.WriteLine("Amount not
available");
}
}
}
public static void Main() {
Account a = new Account(); Not synchronized
Thread t1 = new Thread(a.withdraw);
t1.Name = "t1";
Thread t2 = new Thread(a.withdraw);
t2.Name = "t2";
t1.Start(500);t2.Start(750);
Account a1 = new Account(); Synchronized
a1=Account.Synchronized(a1);
This should have
Thread t3 = new Thread(a1.withdraw); been the default
t3.Name = "t3"; behaviour
Thread t4 = new Thread(a1.withdraw);
t4.Name = "t4";
t3.Start(500); t4.Start(750); }}
balance after withdraw is 500
Output: balance after withdraw is -250 This clearly demonstrated problem
balance after withdraw is 500 if threads are not synchronized.
Amount not available
Points to note
• Don’t Overuse Synchronization
• Beware of Deadlocks

• Can you think of a situation when deadlock can


occur?
Mointor Class
• The lock statement in turn calls the Monitor
class’s Enter() method. Exit() method of the
Monitor class releases the lock.
• Instead of using lock Mointor’s static method
Enter() and Exit() could also be used.
• The Monitor class also provides the Pulse() and
Wait() methods. The Wait() method tells the
thread to wait until the object protected by the
monitor becomes available.
• The Pulse() method signals that there has been
a change in state, and other waiting threads can
have control of the monitor object.
Example
using System;
using System.Threading;
class MessageBoard{
private String messages = "no messages" ;
public void Reader(){
Thread.Sleep(1000);
try{
Monitor.Enter(this);
if (messages == "no messages"){
Console.WriteLine("{0}
{1}",Thread.CurrentThread.Name, messages);
Console.WriteLine("{0}
waiting...",Thread.CurrentThread.Name);
Monitor.Wait(this);
}
If there are no messages then wait.
Console.WriteLine("{0}
{1}",Thread.CurrentThread.Name, messages);
}
finally{
Monitor.Exit(this);
}}
Note how Monitor is used instead of lock
public void Writer(){
Thread.Sleep(1000);
try{
Monitor.Enter(this);
messages = "Have a good day!";
Console.WriteLine("{0} Done writing message...",
Thread.CurrentThread.Name);
Monitor.Pulse(this);
}
finally{ Signal waiting threads that there's data to be read
Monitor.Exit(this);
}}
public static void Main()
{
MessageBoard myMessageBoard = new
MessageBoard();
Thread reader = new Thread(new
ThreadStart(myMessageBoard.Reader));
reader.Name = "ReaderThread:";
Thread writer = new Thread( new
ThreadStart(myMessageBoard.Writer));
writer.Name = "WriterThread:";

reader.Start(); On executing….
writer.Start();
ReaderThread: no messages
} ReaderThread: waiting...
} WriterThread: Done writing
message...
ReaderThread: Have a good day!

Вам также может понравиться