In the print dialog, choose "Save as PDF" as the destination.
Operating Systems 1, Lab 5
One main thread, then many: create, start, pass data, wait, and watch every state
Thread classParameterizedThreadStart, then type-safely; get a result back with a callbackThreadState through Start, Sleep and JoinMain endsPart 1
Who actually runs your code?
Multitasking: a browser, Visual Studio and Notepad open at the same time
Operating system
runs many applications
Process
one per application, own PID
Thread
executes the code
MainSystem.ThreadingCurrentThread is static; Name belongs to the thread object. Predict the first two lines.
Thread t = Thread.CurrentThread;
Console.WriteLine("Name before: [" + t.Name + "]");
Console.WriteLine("Name is null: " + (t.Name == null));
t.Name = "Main Thread";
Console.WriteLine("t.Name: " + t.Name);
Console.WriteLine("Thread.CurrentThread.Name: " + Thread.CurrentThread.Name);Name before: []
Name is null: True
t.Name: Main Thread
Thread.CurrentThread.Name: Main ThreadPart 2
What waiting costs, and how threads avoid it
Main calls Method1(), Method2(), Method3() and times itself. Predict: when does Method3 start? How long does Main take?
static void Method2()
{
for (int i = 1; i <= 3; i++)
{
if (i == 2)
{
Console.WriteLine("Method2: database operation started");
Thread.Sleep(5000); // pretend this is a slow DB call
Console.WriteLine("Method2: database operation completed");
}
Console.WriteLine("Method2: " + i);
}
}Main started
Method1: 1
Method1: 2
Method1: 3
Method2: 1
Method2: database operation started
Method2: database operation completed
Method2: 2
Method2: 3
Method3: 1
Method3: 2
Method3: 3
Main ended after 5.0 sMethod3 waited 5 s for a database call it does not needFix: give each method its own thread. Predict: same order every run? When does Main end?
Stopwatch sw = Stopwatch.StartNew();
Thread.CurrentThread.Name = "Main";
Console.WriteLine("Main started");
Thread t1 = new Thread(Method1) { Name = "Thread1" };
Thread t2 = new Thread(Method2) { Name = "Thread2" };
Thread t3 = new Thread(Method3) { Name = "Thread3" };
t1.Start();
t2.Start();
t3.Start();
Console.WriteLine("Main ended after " + sw.Elapsed.TotalSeconds.ToString("0.0") + " s");The order in which the loops printed their numbers, from three real runs
| Run | Order of the loop lines | Main ended after |
|---|---|---|
| 1 | Method1 1-3, Method2 1, Method3 1-3, Method2 2-3 | 0.1 s |
| 2 | Method1 1, Method2 1, Method1 2-3, Method3 1-3, Method2 2-3 | 0.0 s |
| 3 | Method3 1-3, Method1 1-3, Method2 1, Method2 2-3 | 0.1 s |
Each thread gets a short time slice; an unfinished thread waits for its next turn
t1
slice
t2
slice
t3
slice
t1
again
t2
again
Main thread
created by the process, starts at Main
t1
worker
t2
worker
t3
worker
Part 3
Entry points, data in, results out
Predict: does this compile?
class MyThread : Thread
{
}Program.cs(4,18): error CS0509: 'MyThread': cannot derive from sealed type 'Thread'| Member | Meaning |
|---|---|
Thread.CurrentThread | static: the thread executing this line |
Name | get or set the name (null by default) |
ThreadState | the current state of the thread |
IsAlive | True from Start until the thread ends |
IsBackground | get or set: background or foreground thread |
A thread needs an entry point: a pointer to the method it starts in
| Delegate | Matches | Start with |
|---|---|---|
ThreadStart | void M() | t.Start() |
ParameterizedThreadStart | void M(object x) | t.Start(value) |
void: a thread method cannot return a value directlyobjectDisplayNumbers() prints its thread's name and 1 2 3. Predict the output.
Thread t1 = new Thread(DisplayNumbers) { Name = "t1" };
ThreadStart ts = new ThreadStart(DisplayNumbers);
Thread t2 = new Thread(ts) { Name = "t2" };
Thread t3 = new Thread(new ThreadStart(DisplayNumbers)) { Name = "t3" };
Thread t4 = new Thread(delegate () { DisplayNumbers(); }) { Name = "t4" };
Thread t5 = new Thread(() => DisplayNumbers()) { Name = "t5" };Run 1 Run 2 Run 3
t1: 1 2 3 t1: 1 2 3 t2: 1 2 3
t4: 1 2 3 t2: 1 2 3 t4: 1 2 3
t2: 1 2 3 t3: 1 2 3 t3: 1 2 3
t5: 1 2 3 t5: 1 2 3 t1: 1 2 3
t3: 1 2 3 t4: 1 2 3 t5: 1 2 3Predict: does new Thread(Sum) compile?
Thread t1 = new Thread(Sum);
t1.Start();
static int Sum()
{
int result = 0;
for (int i = 1; i <= 5; i++)
result += i;
return result;
}The method takes one object; the value goes into Start
Program obj = new Program();
Thread t1 = new Thread(obj.DisplayNumbers);
t1.Start(5);
public void DisplayNumbers(object max)
{
int number = Convert.ToInt32(max);
for (int i = 1; i <= number; i++)
Console.WriteLine("Number: " + i);
}Number: 1
Number: 2
Number: 3
Number: 4
Number: 5Start(5) passes 5 to the delegate, which passes it to maxConvert.ToInt32 turns the object back into an intChange one line to t1.Start("hi"); Predict: compile error, or something else?
object parameter accepts any valueclass NumberHelper
{
private int _number;
public NumberHelper(int number)
{
_number = number;
}
public void DisplayNumbers()
{
for (int i = 1; i <= _number; i++)
Console.WriteLine("Number: " + i);
}
}ThreadStartnew Thread(obj.DisplayNumbers) after obj = new NumberHelper(5)Same mistake as before, now with the helper class. Predict: when is it caught?
NumberHelper obj = new NumberHelper("hi");
Thread t1 = new Thread(obj.DisplayNumbers);
t1.Start();Program.cs(24,45): error CS1503: Argument 1: cannot convert from 'string' to 'int'public delegate void ResultCallback(int result);
public void CalculateSum()
{
int result = 0;
for (int i = 1; i <= _number; i++)
{
Console.WriteLine(i);
result = result + i;
}
if (_callback != null)
_callback(result);
}Predict the last line (the output ends with its last 3 of 11 lines). S = the sum.
ResultCallback callback = new ResultCallback(ShowResult);
NumberHelper obj = new NumberHelper(10, callback);
Thread t1 = new Thread(obj.CalculateSum);
t1.Start();
static void ShowResult(int result)
{
Console.WriteLine("Sum of the numbers is: " + result);
}9
10
Sum of the numbers is: 55Part 4
States, Sleep, Join, foreground and background
| Life-cycle state | ThreadState | When |
|---|---|---|
| Unstarted | Unstarted | created, Start not called yet |
| Ready / running | Running | started and not blocked |
| Not runnable | WaitSleepJoin | blocked in Sleep, Join, or waiting |
| Dead | Stopped | its method has finished |
Unstarted
Running
WaitSleepJoin
Running
again
Stopped
Predict lines 1 to 5 before revealing
Thread t = new Thread(Work);
Console.WriteLine("1) after new: " + t.ThreadState + ", IsAlive = " + t.IsAlive);
t.Start();
Thread.Sleep(500); // give the worker time to reach its Sleep
Console.WriteLine("3) while it sleeps: " + t.ThreadState + ", IsAlive = " + t.IsAlive);
t.Join();
Console.WriteLine("5) after Join: " + t.ThreadState + ", IsAlive = " + t.IsAlive);
static void Work()
{
Console.WriteLine("2) inside Work: " + Thread.CurrentThread.ThreadState);
Thread.Sleep(2000);
Console.WriteLine("4) Work is about to end");
}1) after new: Unstarted, IsAlive = False
2) inside Work: Running
3) while it sleeps: WaitSleepJoin, IsAlive = True
4) Work is about to end
5) after Join: Stopped, IsAlive = FalseRunningMain slept 0.5 s, so the worker is inside its 2 s SleepJoin returned only after Work endedProcessSleep loops i = 0 to 5 and calls Thread.Sleep(4000) each pass; Main starts it, joins it, and prints the time. Predict TotalTime.
static void ProcessSleep()
{
for (int i = 0; i <= 5; i++)
{
Console.WriteLine("work is in progress..!");
Thread.Sleep(4000); // sleep for 4 seconds
}
}TotalTime 00:00:24
work completed..!t.Join() makes the calling thread wait until t ends. Predict the output without the Join line.
Thread oThread = new Thread(MethodJoin); // prints "work is in progress..!" 3 times
oThread.Start();
oThread.Join();
Console.WriteLine("work completed..!");| With Join | Without Join (6 of 6 runs) |
|---|---|
work is in progress..! | work completed..! |
work is in progress..! | work is in progress..! |
work is in progress..! | work is in progress..! |
work completed..! | work is in progress..! |
| Foreground (default) | Background | |
|---|---|---|
IsBackground | False | True |
| Main thread ends first | keeps running to the end | stopped with the last foreground thread |
| Keeps the program alive | yes | no |
Predict the output, and how long the program runs
Thread oThread = new Thread(WorkThread);
oThread.Start();
Console.WriteLine("Main Thread Quits..!");
static void WorkThread()
{
for (int i = 0; i <= 4; i++)
{
Console.WriteLine("Worker Thread is in progress..!");
Thread.Sleep(2000); // sleep for 2 seconds
}
Console.WriteLine("Worker Thread Quits..!");
}Worker Thread is in progress..!
Main Thread Quits..!
Worker Thread is in progress..!
Worker Thread is in progress..!
Worker Thread is in progress..!
Worker Thread is in progress..!
Worker Thread Quits..!Main quit at onceAdd one line before Start. Predict the output.
Thread oThread = new Thread(WorkThread);
oThread.IsBackground = true;
oThread.Start();
Console.WriteLine("Main Thread Quits..!");Main Thread Quits..!
Worker Thread is in progress..!Looking ahead
System.Threading.Tasks.Task runs an action on a separate thread for you. Predict: which line comes right after Main thread started?
Console.WriteLine("Main thread started");
Task task = new Task(() =>
{
Console.WriteLine("Running task in separate thread");
int result = AddNumbers(5, 10);
Console.WriteLine("Result of addition: " + result);
});
task.Start();
Console.WriteLine("Main thread is done");
Console.ReadLine();Main thread started
Main thread is done
Running task in separate thread
Result of addition: 15Part 5
About 30 minutes: predict on paper, then run it and check
About 5 minutes: predict every line, in order
Thread t = new Thread(Work) { Name = "Worker" };
Console.WriteLine("A: " + t.ThreadState);
Console.WriteLine("B: " + t.IsBackground);
t.Start();
Thread.Sleep(1000);
Console.WriteLine("C: " + t.ThreadState + " " + t.IsAlive);
t.Join();
Console.WriteLine("D: " + t.ThreadState + " " + t.IsAlive);
static void Work()
{
Thread me = Thread.CurrentThread;
Console.WriteLine("W: " + me.Name + " " + me.ThreadState);
Thread.Sleep(3000);
}A: Unstarted
B: False
W: Worker Running
C: WaitSleepJoin True
D: Stopped FalseRunningSleepAbout 6 minutes
Predict both times. And without the three Join calls?
Stopwatch sw = Stopwatch.StartNew();
Download(); Resize(); Save();
Console.WriteLine("One thread: " + sw.Elapsed.TotalSeconds.ToString("0.0") + " s");
sw.Restart();
Thread t1 = new Thread(Download);
Thread t2 = new Thread(Resize);
Thread t3 = new Thread(Save);
t1.Start(); t2.Start(); t3.Start();
t1.Join(); t2.Join(); t3.Join();
Console.WriteLine("Three threads: " + sw.Elapsed.TotalSeconds.ToString("0.0") + " s");
static void Download() { Thread.Sleep(2000); }
static void Resize() { Thread.Sleep(3000); }
static void Save() { Thread.Sleep(1000); }One thread: 6.0 s
Three threads: 3.0 sAbout 8 minutes
FactorialHelper: it computes n! (1 x 2 x ... x n) on a separate threadn in a type-safe way5! = 120Main, compute 5! then 10!, each on its own thread; 5! must print firstnew FactorialHelper("5", ShowResult)?With public delegate void FactorialCallback(int n, long result);
public FactorialHelper(int n, FactorialCallback callback)
{ _n = n; _callback = callback; }
public void Calculate()
{
long result = 1;
for (int i = 2; i <= _n; i++)
result = result * i;
if (_callback != null)
_callback(_n, result);
}5! = 120
10! = 3628800t.Join() after the first thread keeps 5! first"5": error CS1503, cannot convert from 'string' to 'int'About 5 minutes
Predict the output as written, then with worker.IsBackground = true; before Start
Thread worker = new Thread(Tick);
worker.Start();
Thread.Sleep(1500);
Console.WriteLine("Main done");
static void Tick()
{
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("tick " + i);
Thread.Sleep(1000);
}
Console.WriteLine("Worker done");
}Each version: the same output in 10 of 10 runs
| Foreground (as written) | Background |
|---|---|
tick 1 | tick 1 |
tick 2 | tick 2 |
Main done | Main done |
tick 3 | (nothing more) |
Worker done |
About 6 minutes
Thread t = new Thread(PrintSquares);
t.Start(4);
t.Join();
Console.WriteLine("Main done");
static void PrintSquares(object max)
{
int n = Convert.ToInt32(max);
for (int i = 1; i <= n; i++)
Console.WriteLine(i + " x " + i + " = " + (i * i));
}t.Start("four")?void A(), void B(object x), void C(int x), int D()?1 x 1 = 1
2 x 2 = 4
3 x 3 = 9
4 x 4 = 16
Main done| Method | new Thread(M) |
|---|---|
void A() | ThreadStart |
void B(object x) | ParameterizedThreadStart |
void C(int x) | error CS1503 |
int D() | error CS1503 |
new Thread(method) + Start(): the methods run side by side, in an unpredictable orderThreadStart or ParameterizedThreadStart: void, no parameter or one objectSleep and Join put a thread in WaitSleepJoin; a finished thread is StoppedMahmoud Abas|C# Threads Basics