Threads in C#blk/distributedComputing/Using... · 2009. 4. 27. · Threads in C# • This is a very brief introduction to using threads in C#; we will use Visual Studio 2008 • Many

Post on 12-Oct-2020

0 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

Transcript

Threads in C#• This is a very brief introduction to using threads in C#; we will use Visual Studio 2008

• Many of these examples were taken from the online tutorial  Threading in C# by Joseph Albahari

• A link to this tutorial is

http://www.albahari.com/threading/p // / g/

A First Exampleclass ThreadTest {class ThreadTest {static void Main() {Thread t = new Thread(WriteY);t Start(); // Run WriteY on the new threadt.Start(); // Run WriteY on the new threadwhile (true) Console.Write ("x"); // Write 'x' forever

}}static void WriteY() {while (true) Console.Write ("y"); // Write 'y' foreverConsole.Write ( y ); // Write y forever

}}

xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ……

Passing Parameters to Startl Th dT t {class ThreadTest {static void Main() {

Thread t = new Thread (Go);t.Start (true); // == Go (true) Go (false);

}}static void Go (object upperCase) {

bool upper = (bool) upperCase;C l W it Li ( ? "HELLO!" "h ll !")Console.WriteLine (upper ? "HELLO!" : "hello!");

}}

HELLO!hello!

Naming Threadsl Th dN i {class ThreadNaming {static void Main() {

Thread.CurrentThread.Name = "main";Thread worker = new Thread (Go);worker.Name = "worker";worker.Start();o e .Sta t();Go();

}static void Go() {static void Go() {

Console.WriteLine ("Hello from " + Thread.CurrentThread.Name);

}}

Hello from mainHello from worker

Simple Blocking Methods• Construct PurposeSleep Blocks for a given time period.Join Waits for another thread to finish.

Details on Thread Sleeping

static void Main() { Thread.Sleep (0); // relinquish CPU time-slice Thread.Sleep (1000); // sleep for 1000 millisecondsThread.Sleep (1000); // sleep for 1000 milliseconds Thread.Sleep (TimeSpan.FromHours (1)); // sleep 1 hour Thread.Sleep (Timeout.Infinite); // sleep until interrupted

}

Example of Using Joinl J i D {class JoinDemo { static void Main() {

Thread t = new Thread (delegate() { Console ReadLine(); });delegate() { Console.ReadLine(); });

t.Start();t.Join(); // Wait until thread t finishes Console.WriteLine ("Thread t's ReadLine complete!");Co so e. te e ( ead t s ead e co p ete! );

}}

• What will happen when this program is run?

Locking ConstructsC t t P C P ? S d• Construct Purpose Cross‐Process? Speed

• Lock Ensures just one thread can access a                    no                         fast

resource, or section of code. 

• Mutex Ensures just one thread can access a resource,   yes                   moderateor section of code.

• Semaphore Ensures not more than a specified number of     yes                   moderate threads can access a resource, or section of code.

Making Threads Safe ‐ 1• A class that is not thread safe

class ThreadUnsafe {class ThreadUnsafe {static int val1, val2;static void Go() {if (val2 != 0) ( a ! 0)

Console.WriteLine (val1 / val2);val2 = 0;

}}

Wh i hi id d f ?• Why is this considered unsafe?

Making Threads Safe ‐ 2• Making the class thread safe

class ThreadSafe {class ThreadSafe {static object locker = new object();static int val1, val2;static void Go() {stat c o d Go() {lock (locker) {

if (val2 != 0) Console.WriteLine (val1 / val2);

val2 = 0;}

}}

Interrupt and Abort• Calling Interrupt on a blocked thread forcibly releases it, throwing a ThreadInterruptedExceptionclass Program {

static void Main() {Thread t = new Thread (delegate() {

t { Th d Sl (Ti t I fi it )try { Thread.Sleep(Timeout.Infinite);} catch (ThreadInterruptedException){

Console.Write("Forcibly");}}Console.WriteLine ("Woken!"); });

t.Start();t.Interrupt();p ();

}}

• This program prints• This program prints   Forcibly Woken!

Using the Synchronization Attributei S tusing System;

using System.Threading;using System.Runtime.Remoting.Contexts;[Synchronization][ y ]public class AutoLock : ContextBoundObject {public void Demo() {Console.Write ("Start...");Thread Sleep (1000); // We can't be preempted hereThread.Sleep (1000); // We can't be preempted hereConsole.WriteLine ("end"); // thanks to automatic locking!

} }public class Test {public static void Main() {AutoLock safeInstance = new AutoLock();new Thread (safeInstance Demo) Start();// Call the Demonew Thread (safeInstance.Demo).Start();// Call the Demonew Thread (safeInstance.Demo).Start();// method 3 timessafeInstance.Demo(); // concurrently.

}}

• What will be printed by this program?

Mutual Exclusionl O AtATi Pl {class OneAtATimePlease {// Use a name unique to the application static Mutex mutex = new

Mutex (false "oreilly com OneAtATimeDemo");Mutex (false, oreilly.com OneAtATimeDemo );static void Main() { // Wait 5 seconds if contended if (!mutex.WaitOne (TimeSpan.FromSeconds (5), false))

{Console.WriteLine ("Another instance is running.);{Co so e. te e ( ot e sta ce s u g.);return;

}try {

Console.WriteLine ("Running - press Enter to exit");

Console.ReadLine();} finally { mutex.ReleaseMutex(); }

}}

• What will happen when this program is run?

Semaphoresl S h T t {class SemaphoreTest {static Semaphore s = new Semaphore (3, 3);// Available=3; Capacity=3static void Main() {static void Main() {for (int i = 0; i < 10; i++)

new Thread (Go).Start();}}static void Go() {

while (true) {s.WaitOne();Thread.Sleep (100);// Only 3 threads can get here at onces.Release();

}}}

WaitAny, WaitAll and SignalAndWaitI dditi t th S t d W itO th d th• In addition to the Set and WaitOne methods, there are three static methods on the WaitHandle class

• WaitHandle.WaitAny waits for any one of an array of wait handles; WaitHandle.WaitAll waits on all of the given handles

• SignalAndWait is perhaps the most useful: it calls WaitOne on one WaitHandle, while calling Set on another WaitHandle– The first thread does the following:

WaitHandle.SignalAndWait (wh1, wh2);

– While the second thread does the opposite:WaitHandle.SignalAndWait (wh2, wh1);

The Dining Philosopher• The dining table with five philosophers

0

l d

4 1salad

3 2

A First Attempt at a SolutionS th h ti k h th f ll i id th• Suppose the chopsticks have the following ids: the chopstick to the right of philosopher j is labeled j; th h ti k t th l ft i l b l d j+1 d (ithe chopstick to the left is labeled j+1 mod n (in our problem n = 5)

• Each philosopher j follows this routine after entering and sitting at the table: pick up the chopstick on the right; pickup the chopstick on the left;  eat some salad; put down the chopstick on the right; put down the chopstick on the left; leave the dining room to go think

• As we have learned previously, this solution can deadlock

C# Implementation ‐ 1namespace DiningPhilosophersSemaphore {namespace DiningPhilosophersSemaphore {public class DiningPhilosophersMain {

static void Main(string[] args){int numOfPhilosophers = 5;p ;Thread[] t = new Thread[numOfPhilosophers];Semaphore[] s = new Semaphore[numOfPhilosophers];for(int i = 0; i < numOfPhilosophers; i++) {

//Semaphore(starting num of permits,total num of permits)s[i] = new Semaphore(1, 1);

}DiningPhilosophersMain phil = new DiningPhilosophersMain();DiningPhilosophersMain phil = new DiningPhilosophersMain();for(int i = 0; i < numOfPhilosophers; i++){t[i] = new Thread(phil.start);t[i].Start(new DiningPhilosopher[ ] ( g p

(i, new Random().Next(500), s, numOfPhilosophers));}Thread.Sleep(10000);S t C l W it Li ("All th d d ")System.Console.WriteLine("All threads done.");Environment.Exit(0);

}

C# Implementation ‐ 2private void start(Object args) {private void start(Object args) {

DiningPhilosopher philosopher = (DiningPhilosopher)args;while (true) {

think(philosopher);(p p );acquireChopstick(right(philosopher.id, philosopher), philosopher);Thread.Sleep(500); // this will cause deadlockacquireChopstick(left(philosopher.id, philosopher), philosopher);eat(philosopher);releaseChopstick(right(philosopher.id, philosopher), philosopher);releaseChopstick(left(philosopher.id, philosopher), philosopher);

}}}

private void acquireChopstick(int i, DiningPhilosopher philosopher){p q p ( , g p p p ){philosopher.chopsticks[i].WaitOne();System.Console.WriteLine("Philosopher " + philosopher.id +

" is picking up chopstick " + i);}

C# Implementation ‐ 3private void releaseChopstick(int i DiningPhilosopher philosopher){private void releaseChopstick(int i, DiningPhilosopher philosopher){

philosopher.chopsticks[i].Release();System.Console.WriteLine("Philosopher " + philosopher.id +

" is putting chopstick " + i + " down.");}private void eat(DiningPhilosopher philosopher){

int time = new Random().Next(philosopher.sleep);l i i ( hil h hil h idSystem.Console.WriteLine("Philosopher " + philosopher.id +

" is eating for " + time + " ms.");Thread.Sleep(time);

}}private void think(DiningPhilosopher philosopher) {

int time = new Random().Next(philosopher.sleep);System.Console.WriteLine("Philosopher " + philosopher.id +

"i thi ki f " ti " ")"is thinking for " + time + " ms.");Thread.Sleep(time);System.Console.WriteLine("Philosopher " + philosopher.id +

"is done thinking.");gSystem.Console.WriteLine("Philosopher " + philosopher.id +

"is entering dining room.");}

C# Implementation ‐ 4private int right(int i, DiningPhilosopher philosopher) {private int right(int i, DiningPhilosopher philosopher) {

return (i++) % philosopher.numOfPhils;}private int left(int i, DiningPhilosopher philosopher) {

return (philosopher.numOfPhils + i - 1) % philosopher.numOfPhils;}

}l Di i Phil h {class DiningPhilosopher {public int id { get; set; }public int sleep { get; set; }public Semaphore[] chopsticks { get; set; }p p [] p { g ; ; }public int numOfPhils { get; set; }public DiningPhilosopher(int id, int sleep, Semaphore[] chopsticks,

int numOfPhils) {this.id = id;this.sleep = sleep;this.chopsticks = chopsticks;this numOfPhils = numOfPhils;this.numOfPhils = numOfPhils;

}}

}

Limiting Access to the Dining Room• A simple solution to the possible starvation problem with the dining philosophers is to limited access to the dining room to n‐1 philosophers

• Suppose the semaphore diningroom has been initialized to n‐1 then the philosopher would first request to enter the dining room via this counting semaphore then, after eating and putting down the chopsticks, would release the semaphore

In‐Class Lab Activity• Introduce a counting semaphore into the given dining philosopher program

• Verify that limiting the number of philosophers in the room to n‐1 breaks the deadlock caused by the delays introduced between pick up right fork and pick up left fork

• Verify that if n philosophers are allowed in the room then the deadlock reappearspp

• This lab activity is described in more detail on a separate lab sheetseparate lab sheet

top related