Presentation is loading. Please wait.

Presentation is loading. Please wait.

 2002 Prentice Hall. All rights reserved. Chapter 19 - Multithreading Outline 19.1 Introduction 19.2 Thread States: Life Cycle of a Thread 19.3 threading.Thread.

Similar presentations


Presentation on theme: " 2002 Prentice Hall. All rights reserved. Chapter 19 - Multithreading Outline 19.1 Introduction 19.2 Thread States: Life Cycle of a Thread 19.3 threading.Thread."— Presentation transcript:

1  2002 Prentice Hall. All rights reserved. Chapter 19 - Multithreading Outline 19.1 Introduction 19.2 Thread States: Life Cycle of a Thread 19.3 threading.Thread Example 19.4 Thread Synchronization 19.5 Producer/Consumer Relationship without Thread Synchronization 19.6 Producer/Consumer Relationship with Thread Synchronization 19.7 Producer/Consumer Relationship: Module Queue 19.8 Producer/Consumer Relationship: The Circular Buffer 19.9 Semaphores 19.10 Events

2  2002 Prentice Hall. All rights reserved. 19.1 Introduction Threads often called “light-weight” process because operating systems generally require fewer resources to create and manage threads than to create and manage processes Python’s threading capabilities depend on whether the operating system supports multithreading Python’s threading module provides its multithreading capabilities

3  2002 Prentice Hall. All rights reserved. 19.2 Thread States: Life Cycle of a Thread Python interpreter controls all program threads Python’s global interpreter lock (GIL) ensures that the interpreter runs only one thread at any given time Thread is said to be in one of several thread states at any time Python programs can define threads by inheriting from class threading.Thread and overriding its functionality

4  2002 Prentice Hall. All rights reserved. 19.2 Thread States: Life Cycle of a Thread Newly created thread begins its lifecycle in the born state Invoking the thread’s start method places the thread in the ready state The thread’s run method, which implements the tasks that the thread performs, obtains the GIL and enters the running state Thread enters the dead state when its run method returns or terminates for any reason (e.g., an uncaught exception)

5  2002 Prentice Hall. All rights reserved. 19.2 Thread States: Life Cycle of a Thread A running thread that calls another thread’s join method forfeits the GIL and waits for the join ed thread to die before proceeding Thread enters the blocked state while it waits for a requested, unavailable resource (e.g. I/O device) When a running thread calls function time.sleep, it releases the GIL and enters the sleeping state

6  2002 Prentice Hall. All rights reserved. 19.2 Thread States: Life Cycle of a Thread Deadlock occurs when one or more threads wait forever for an event that cannot occur In indefinite postponement, one or more threads is delayed for some unpredictably long time

7  2002 Prentice Hall. All rights reserved. 19.2 Thread States: Life Cycle of a Thread Fig. 19.1 State diagram showing the life cycle of a thread.

8  2002 Prentice Hall. All rights reserved. 19.2 Thread States: Life Cycle of a Thread Module threading provides ways for a program to obtain information about its threads, including their current states –Function threading.currentThread returns reference to currently running Thread object –Function threading.enumerate returns list of currently active Thread objects –Function threading.activeCount returns length of list returned by threading.enumerate –Method isAlive returns 1 if the Thread object’s start method bas been invoked and the Thread object is not dead –Methods setName and getName allow programmer to set and get a Thread object’s name, respectively

9  2002 Prentice Hall. All rights reserved. 19.3 threading.Thread example Threads can be created by defining a class that derives from threading.Thread and instantiating objects of that class

10  2002 Prentice Hall. All rights reserved. Outline fig19_02.py 1 # Fig. 19.2: fig19_02.py 2 # Multiple threads printing at different intervals. 3 4 import threading 5 import random 6 import time 7 8 class PrintThread( threading.Thread ): 9 """Subclass of threading.Thread""" 10 11 def __init__( self, threadName ): 12 """Initialize thread, set sleep time, print data""" 13 14 threading.Thread.__init__( self, name = threadName ) 15 self.sleepTime = random.randrange( 1, 6 ) 16 print "Name: %s; sleep: %d" % \ 17 ( self.getName(), self.sleepTime ) 18 19 # overridden Thread run method 20 def run( self ): 21 """Sleep for 1-5 seconds""" 22 23 print "%s going to sleep for %s second(s)" % \ 24 ( self.getName(), self.sleepTime ) 25 time.sleep( self.sleepTime ) 26 print self.getName(), "done sleeping" 27 28 thread1 = PrintThread( "thread1" ) 29 thread2 = PrintThread( "thread2" ) 30 thread3 = PrintThread( "thread3" ) 31 32 print "\nStarting threads" 33 Module threading provides multithreading capabilitiesThread class derived from base class threading.Thread Calls base-class constructor with object and the thread’s name Keyword name specifies Thread object’s name Thread object has randomly selected sleepTime attributeReturn Thread object’s nameOverridden Thread run methodInstantiate PrintThread object

11  2002 Prentice Hall. All rights reserved. Outline fig19_02.py 34 thread1.start() # invokes run method of thread1 35 thread2.start() # invokes run method of thread2 36 thread3.start() # invokes run method of thread3 37 38 print "Threads started\n" Name: thread1; sleep: 5 Name: thread2; sleep: 1 Name: thread3; sleep: 3 Starting threads Name: thread1; sleep: 5 Name: thread2; sleep: 1 Name: thread3; sleep: 3 Starting threads thread1 going to sleep for 5 second(s) thread2 going to sleep for 1 second(s) thread3 going to sleep for 3 second(s) Threads started thread2 done sleeping thread3 done sleeping thread1 done sleeping Thread object enters ready state by invoking start method

12  2002 Prentice Hall. All rights reserved. 19.4 Thread Synchronization Sections of code that access shared data are referred to as critical sections Mutual exclusion or thread synchronization ensures a thread accessing the shared data excludes all other threads from doing so simultaneously Module threading provides several thread- synchronization mechanisms (e.g., locks and condition variables)

13  2002 Prentice Hall. All rights reserved. 19.4 Thread Synchronization Class threading.RLock creates lock objects –Method acquire causes lock to enter locked state –Only one thread may acquire lock at a time so system places any other threads who attempt to acquire lock in blocked state –When the thread that owns the lock invokes method release, the lock enters the unlocked state and blocked threads receive a notification so one can acquire the lock

14  2002 Prentice Hall. All rights reserved. 19.4 Thread Synchronization Condition variables monitor the state of an object or notify a thread when an event occurs –Created with class threading.Condition –Provides acquire and release method because condition variable contains underlying locks –Method wait causes calling thread to release lock lock and block until it is awakened again –Method notify wakes up one thread waiting on the condition variable –Method notifyAll wakes up all waiting threads

15  2002 Prentice Hall. All rights reserved. 19.5 Producer/Consumer Relationship without Thread Synchronization Producer portion of application generates data Consumer portion of application uses that data Producer thread calls produce method to generate data and place it into a shared memory region called a buffer Consumer thread calls consumer method to read data from the buffer

16  2002 Prentice Hall. All rights reserved. Outline fig19_03.py 1 # Fig. 19.3: fig19_03.py 2 # Multiple threads modifying shared object. 3 4 from UnsynchronizedInteger import UnsynchronizedInteger 5 from ProduceInteger import ProduceInteger 6 from ConsumeInteger import ConsumeInteger 7 8 # initialize integer and threads 9 number = UnsynchronizedInteger() 10 producer = ProduceInteger( "Producer", number, 1, 4 ) 11 consumer = ConsumeInteger( "Consumer", number, 4 ) 12 13 print "Starting threads...\n" 14 15 # start threads 16 producer.start() 17 consumer.start() 18 19 # wait for threads to terminate 20 producer.join() 21 consumer.join() 22 23 print "\nAll threads have terminated." Create shared UnsynchronizedInteger object number Instantiate ProduceInteger thread objectCreate ConsumeInteger thread objectInvoke thread object’s start methods Ensures that main program waits for both threads to terminate before proceeding

17  2002 Prentice Hall. All rights reserved. Outline fig19_03.py Starting threads... Consumer reads – 1 Consumer reads – 1 Producer writes 1 Consumer reads 1 Producer writes 2 Consumer reads 2 Consumer read values totaling: 1. Terminating Consumer. Producer writes 3 Producer writes 4 Producer done producing. Terminating Producer. All threads have terminated. Starting threads... Producer writes 1 Producer writes 2 Producer writes 3 Consumer reads 3 Producer writes 4 Producer done producing. Terminating Producer. Consumer reads 4 Consumer reads 4 Consumer reads 4 Consumer read values totaling: 15. Terminating Consumer. All threads have terminated.

18  2002 Prentice Hall. All rights reserved. Outline Starting threads... Producer writes 1 Consumer reads 1 Producer writes 2 Consumer reads 2 Producer writes 3 Consumer reads 3 Producer writes 4 Producer done producing. Terminating Producer. Consumer reads 4 Consumer read values totaling: 10. Terminating Consumer. All threads have terminated

19  2002 Prentice Hall. All rights reserved. Outline ProduceInteger.p y 1 # Fig. 19.4: ProduceInteger.py 2 # Integer-producing class. 3 4 import threading 5 import random 6 import time 7 8 class ProduceInteger( threading.Thread ): 9 """Thread to produce integers""" 10 11 def __init__( self, threadName, sharedObject, begin, end ): 12 """Initialize thread, set shared object""" 13 14 threading.Thread.__init__( self, name = threadName ) 15 self.sharedObject = sharedObject 16 self.begin = begin 17 self.end = end 18 19 def run( self ): 20 """Produce integers in given range at random intervals""" 21 22 for i in range( self.begin, ( self.end + 1 ) ): 23 time.sleep( random.randrange( 4 ) ) 24 self.sharedObject.set( i ) 25 26 print "%s done producing." % self.getName() 27 print "Terminating %s." % self.getName() Subclass of threading.Thread Set variable sharedObject to refer to object shared by producer and consumerLoops from begin to end Put ProduceInteger object into sleeping state for random time intervalPrints message indicating that run method has terminated Set shared object

20  2002 Prentice Hall. All rights reserved. Outline ConsumeInteger.p y 1 # Fig. 19.5: ConsumeInteger.py 2 # Integer-consuming queue. 3 4 import threading 5 import random 6 import time 7 8 class ConsumeInteger( threading.Thread ): 9 """Thread to consume integers""" 10 11 def __init__( self, threadName, sharedObject, amount ): 12 """Initialize thread, set shared object""" 13 14 threading.Thread.__init__( self, name = threadName ) 15 self.sharedObject = sharedObject 16 self.amount = amount 17 18 def run( self ): 19 """Consume given amount of values at random time intervals""" 20 21 sum = 0 # total sum of consumed values 22 23 # consume given amount of values 24 for i in range( self.amount ): 25 time.sleep( random.randrange( 4 ) ) 26 sum += self.sharedObject.get() 27 28 print "%s read values totaling: %d." % \ 29 ( self.getName(), sum ) 30 print "Terminating %s." % self.getName() Refers to the shared UnsynchronizedInteger objectSums values of the shared UnsynchronizedInteger object Print total sum of consumed values

21  2002 Prentice Hall. All rights reserved. Outline UnsynchronizedIn teger.py 1 # Fig. 19.6: UnsynchronizedInteger.py 2 # Unsynchronized access to an integer. 3 4 import threading 5 6 class UnsynchronizedInteger: 7 """Class that provides unsynchronized access an integer""" 8 9 def __init__( self ): 10 """Initialize integer to -1""" 11 12 self.buffer = -1 13 14 def set( self, newNumber ): 15 """Set value of integer""" 16 17 print "%s writes %d" % \ 18 ( threading.currentThread().getName(), newNumber ) 19 self.buffer = newNumber 20 21 def get( self ): 22 """Get value of integer""" 23 24 tempNumber = self.buffer 25 print "%s reads %d" % \ 26 ( threading.currentThread().getName(), tempNumber ) 27 28 return tempNumber Provides unsynchronized access to an integerInitialize integer to -1Sets integer to specified valueReturns value of integerUse temporary variable to ensure that program prints correct value

22  2002 Prentice Hall. All rights reserved. 19.6 Producer/Consumer Relationship with Thread Synchronization Producer and consumer can access shared memory cell with synchronization –Ensures that the consumer consumes each value exactly once –Ensures that consumer waits for producer to execute first

23  2002 Prentice Hall. All rights reserved. Outline fig19_07.py 1 # Fig. 19.7: fig19_07.py 2 # Multiple threads modifying shared object. 3 4 from SynchronizedInteger import SynchronizedInteger 5 from ProduceInteger import ProduceInteger 6 from ConsumeInteger import ConsumeInteger 7 8 # initialize number and threads 9 number = SynchronizedInteger() 10 producer = ProduceInteger( "Producer", number, 1, 4 ) 11 consumer = ConsumeInteger( "Consumer", number, 4 ) 12 13 print "Starting threads...\n" 14 15 print "%-35s %-9s%2s\n" % \ 16 ( "Operation", "Buffer", "Occupied Count" ) 17 number.displayState( "Initial state" ) 18 19 # start threads 20 producer.start() 21 consumer.start() 22 23 # wait for threads to terminate 24 producer.join() 25 consumer.join() 26 27 print "\nAll threads have terminated." Create SynchronizedInteger object Start producer and consumer threads

24  2002 Prentice Hall. All rights reserved. Outline Starting threads... Operation Buffer Occupied Count Initial state -1 0 Producer writes 1 1 Consumer reads 1 1 0 Consumer tries to read. Buffer empty. Consumer waits. 1 0 Producer writes 2 2 1 Consumer reads 2 2 0 Producer writes 3 3 1 Producer tries to write. Buffer full. Producer waits. 3 1 Consumer reads 3 3 0 Producer writes 4 4 1 Producer done producing. Terminating Producer. Consumer reads 4 4 0 Consumer read values totaling: 10. Terminating Consumer. All threads have terminated.

25  2002 Prentice Hall. All rights reserved. Outline Starting threads... Operation Buffer Occupied Count Initial state -1 0 Consumer tries to read. Buffer empty. Consumer waits. -1 0 Producer writes 1 1 1 Consumer reads 1 1 0 Producer writes 2 2 1 Consumer reads 2 2 0 Consumer tries to read. Buffer empty. Consumer waits. 2 0 Producer writes 3 3 1 Consumer reads 3 3 0 Producer writes 4 4 1 Producer done producing. Terminating Producer. Consumer reads 4 4 0 Consumer read values totaling: 10. Terminating Consumer. All threads have terminated.

26  2002 Prentice Hall. All rights reserved. Outline Starting threads... Operation Buffer Occupied Count Initial state -1 0 Producer writes 1 1 1 Consumer reads 1 1 0 Producer writes 2 2 1 Consumer reads 2 2 0 Producer writes 3 3 1 Consumer reads 3 3 0 Producer writes 4 4 1 Producer done producing. Terminating Producer. Consumer reads 4 4 0 Consumer read values totaling: 10. Terminating Consumer. All threads have terminated.

27  2002 Prentice Hall. All rights reserved. Outline SynchronizedInte ger.py 1 # Fig. 19.8: SynchronizedInteger.py 2 # Synchronized access to an integer with condition variable. 3 4 import threading 5 6 class SynchronizedInteger: 7 """Class that provides synchronized access an integer""" 8 9 def __init__( self ): 10 """Initialize integer, buffer count and condition variable""" 11 12 self.buffer = -1 13 self.occupiedBufferCount = 0 # number of occupied buffers 14 self.threadCondition = threading.Condition() 15 16 def set( self, newNumber ): 17 """Set value of integer--blocks until lock acquired""" 18 19 # block until lock released then acquire lock 20 self.threadCondition.acquire() 21 22 # while not producer’s turn, release lock and block 23 while self.occupiedBufferCount == 1: 24 print "%s tries to write." % \ 25 threading.currentThread().getName() 26 self.displayState( "Buffer full. " + \ 27 threading.currentThread().getName() + " waits." ) 28 self.threadCondition.wait() 29 30 # (lock has now been re-acquired) 31 32 self.buffer = newNumber # set new buffer value 33 self.occupiedBufferCount += 1 # allow consumer to consume 34 Provides synchronized access to an integerKeeps track of number of occupied buffersCondition variable controls access to integerSets value of integer, blocking until lock acquired Method acquire blocks until lock available Block until producer’s turnSet new buffer value after lock is re-acquired

28  2002 Prentice Hall. All rights reserved. Outline SynchronizedInte ger.py 35 self.displayState( "%s writes %d" % \ 36 ( threading.currentThread().getName(), newNumber ) ) 37 38 self.threadCondition.notify() # wake up a waiting thread 39 self.threadCondition.release() # allow lock to be acquired 40 41 def get( self ): 42 """Get value of integer--blocks until lock acquired""" 43 44 # block until lock released then acquire lock 45 self.threadCondition.acquire() 46 47 # while producer’s turn, release lock and block 48 while self.occupiedBufferCount == 0: 49 print "%s tries to read." % \ 50 threading.currentThread().getName() 51 self.displayState( "Buffer empty. " + \ 52 threading.currentThread().getName() + " waits." ) 53 self.threadCondition.wait() 54 55 # (lock has now been re-acquired) 56 57 tempNumber = self.buffer 58 self.occupiedBufferCount -= 1 # allow producer to produce 59 60 self.displayState( "%s reads %d" % \ 61 ( threading.currentThread().getName(), tempNumber ) ) 62 63 self.threadCondition.notify() # wake up a waiting thread 64 self.threadCondition.release() # allow lock to be acquired 65 66 return tempNumber 67 Wake up a waiting threadAllow lock to be acquiredReturn value of integer when lock acquiredRelease lock and block until consumer’s turnDisplay buffer state

29  2002 Prentice Hall. All rights reserved. Outline SynchronizedInte ger.py 68 def displayState( self, operation ): 69 """Display current state""" 70 71 print "%-35s %-9s%2s\n" % \ 72 ( operation, self.buffer, self.occupiedBufferCount ) Displays current state of buffer

30  2002 Prentice Hall. All rights reserved. 19.7 Producer/Consumer Relationship: Module Queue Module Queue defines class Queue, which is a synchronized implementation of a queue Queue constructor accepts optional argument maxsize Consumer consumes value by calling Queue method get, which removes and returns item from the head of the queue Producer produces value by calling Queue method put, which inserts item at tail of queue

31  2002 Prentice Hall. All rights reserved. Outline fig19_09.py 1 # Fig. 19.9: fig19_09.py 2 # Multiple threads producing/consuming values. 3 4 from Queue import Queue 5 from ProduceToQueue import ProduceToQueue 6 from ConsumeFromQueue import ConsumeFromQueue 7 8 # initialize number and threads 9 queue = Queue() 10 producer = ProduceToQueue( "Producer", queue ) 11 consumer = ConsumeFromQueue( "Consumer", queue ) 12 13 print "Starting threads...\n" 14 15 # start threads 16 producer.start() 17 consumer.start() 18 19 # wait for threads to terminate 20 producer.join() 21 consumer.join() 22 23 print "\nAll threads have terminated." Starting threads... Producer adding 11 to queue Producer adding 12 to queue Consumer attempting to read 11... Consumer read 11 Class Queue is synchronized queue implementation Instantiate infinite-size queueStart producer and consumer threadsMain program waits for consumer and producer threads to terminate

32  2002 Prentice Hall. All rights reserved. Outline fig19_09.py Consumer attempting to read 12... Consumer read 12 Producer adding 13 to queue Consumer attempting to read 13... Consumer read 13 Producer adding 14 to queue Consumer attempting to read 14... Consumer read 14 Consumer attempting to read 15... Producer adding 15 to queue Consumer read 15 Consumer attempting to read 16... Producer adding 16 to queue Consumer read 16 Consumer attempting to read 17... Producer adding 17 to queue Consumer read 17 Producer adding 18 to queue Producer adding 19 to queue Consumer attempting to read 18... Consumer read 18 Consumer attempting to read 19... Consumer read 19 Producer adding 20 to queue Producer finished producing values Terminating Producer Consumer attempting to read 20... Consumer read 20 Consumer retrieved values totaling: 155 Terminating Consumer All threads have terminated.

33  2002 Prentice Hall. All rights reserved. Outline ProduceToQueue.p y 1 # Fig. 19.10: ProduceToQueue.py 2 # Integer-producing class. 3 4 import threading 5 import random 6 import time 7 8 class ProduceToQueue( threading.Thread ): 9 """Thread to produce integers""" 10 11 def __init__( self, threadName, queue ): 12 """Initialize thread, set shared queue""" 13 14 threading.Thread.__init__( self, name = threadName ) 15 self.sharedObject = queue 16 17 def run( self ): 18 """Produce integers in range 11-20 at random intervals""" 19 20 for i in range( 11, 21 ): 21 time.sleep( random.randrange( 4 ) ) 22 print "%s adding %s to queue" % ( self.getName(), i ) 23 self.sharedObject.put( i ) 24 25 print self.getName(), "finished producing values" 26 print "Terminating", self.getName() Producer thread uses synchronized queue Refers to shared synchronized Queue object Place item at tail of the queue

34  2002 Prentice Hall. All rights reserved. Outline ConsumeFromQueue.py 1 # Fig. 19.11: ConsumeFromQueue.py 2 # Integer-consuming queue. 3 4 import threading 5 import random 6 import time 7 8 class ConsumeFromQueue( threading.Thread ): 9 """Thread to consume integers""" 10 11 def __init__( self, threadName, queue ): 12 """Initialize thread, set shared queue""" 13 14 threading.Thread.__init__( self, name = threadName ) 15 self.sharedObject = queue 16 17 def run( self ): 18 """Consume 10 values at random time intervals""" 19 20 sum = 0 # total sum of consumed values 21 current = 10 # last value retrieved 22 23 # consume 10 values 24 for i in range( 10 ): 25 time.sleep( random.randrange( 4 ) ) 26 print "%s attempting to read %s..." % \ 27 ( self.getName(), current + 1 ) 28 current = self.sharedObject.get() 29 print "%s read %s" % ( self.getName(), current ) 30 sum += current 31 32 print "%s retrieved values totaling: %d" % \ 33 ( self.getName(), sum ) 34 print "Terminating", self.getName() Consumer thread using synchronized Queue objectRefers to shared Queue object Get item from head of queue

35  2002 Prentice Hall. All rights reserved. 19.8 Producer/Consumer Relationship: The Circular Buffer Circular buffer provides extra buffers into which the producer can place values and from which the consumer can retrieve those values

36  2002 Prentice Hall. All rights reserved. Outline fig19_12.py 1 # Fig. 19.12: fig19_12.py 2 # Show multiple threads modifying shared object. 3 4 from CircularBuffer import CircularBuffer 5 from ProduceInteger import ProduceInteger 6 from ConsumeInteger import ConsumeInteger 7 8 # initialize number and threads 9 buffer = CircularBuffer() 10 producer = ProduceInteger( "Producer", buffer, 11, 20 ) 11 consumer = ConsumeInteger( "Consumer", buffer, 10 ) 12 13 print "Starting threads...\n" 14 15 buffer.displayState() 16 17 # start threads 18 producer.start() 19 consumer.start() 20 21 # wait for threads to terminate 22 producer.join() 23 consumer.join() 24 25 print "\nAll threads have terminated." Create CircularBuffer object Start producer and consumer threads

37  2002 Prentice Hall. All rights reserved. Outline Starting threads... (buffers occupied: 0) buffers: -1 -1 -1 ---- ---- ---- WR Producer writes 11 (buffers occupied: 1) buffers: 11 -1 -1 ---- ---- ---- R W Consumer reads 11 (buffers occupied: 0) buffers: 11 -1 -1 ---- ---- ---- WR All buffers empty. Consumer waits. Producer writes 12 (buffers occupied: 1) buffers: 11 12 -1 ---- ---- ---- R W Consumer reads 12 (buffers occupied: 0) buffers: 11 12 -1 ---- ---- ---- WR All buffers empty. Consumer waits. Producer writes 13 (buffers occupied: 1) buffers: 11 12 13 ---- ---- ---- W R

38  2002 Prentice Hall. All rights reserved. Outline Consumer reads 13 (buffers occupied: 0) buffers: 11 12 13 ---- ---- ---- WR All buffers empty. Consumer waits. Producer writes 14 (buffers occupied: 1) buffers: 14 12 13 ---- ---- ---- R W Consumer reads 14 (buffers occupied: 0) buffers: 14 12 13 ---- ---- ---- WR Producer writes 15 (buffers occupied: 1) buffers: 14 15 13 ---- ---- ---- R W Producer writes 16 (buffers occupied: 2) buffers: 14 15 16 ---- ---- ---- W R Consumer reads 15 (buffers occupied: 1) buffers: 14 15 16 ---- ---- ---- W R Producer writes 17 (buffers occupied: 2) buffers: 17 15 16 ---- ---- ---- W R

39  2002 Prentice Hall. All rights reserved. Outline Producer writes 18 (buffers occupied: 3) buffers: 17 18 16 ---- ---- ---- WR All buffers full. Producer waits. Consumer reads 16 (buffers occupied: 2) buffers: 17 18 16 ---- ---- ---- R W Producer writes 19 (buffers occupied: 3) buffers: 17 18 19 ---- ---- ---- WR All buffers full. Producer waits. Consumer reads 17 (buffers occupied: 2) buffers: 17 18 19 ---- ---- ---- W R Producer writes 20 (buffers occupied: 3) buffers: 20 18 19 ---- ---- ---- WR Producer done producing. Terminating Producer. Consumer reads 18 (buffers occupied: 2) buffers: 20 18 19 ---- ---- ---- W R

40  2002 Prentice Hall. All rights reserved. Outline Consumer reads 19 (buffers occupied: 1) buffers: 20 18 19 ---- ---- ---- R W Consumer reads 20 (buffers occupied: 0) buffers: 20 18 19 ---- ---- ---- WR Consumer read values totaling: 155. Terminating Consume\r. All threads have terminated

41  2002 Prentice Hall. All rights reserved. Outline CircularBuffer.p y 1 # Fig. 19.13: CircularBuffer.py 2 # Synchronized circular buffer of integer values 3 4 import threading 5 6 class CircularBuffer: 7 8 def __init__( self ): 9 """Set buffer, count, locations and condition variable""" 10 11 # each element in list is a buffer 12 self.buffer = [ -1, -1, -1 ] 13 14 self.occupiedBufferCount = 0 # count of occupied buffers 15 self.readLocation = 0 # current reading index 16 self.writeLocation = 0 # current writing index 17 18 self.threadCondition = threading.Condition() 19 20 def set( self, newNumber ): 21 """Set next buffer index value--blocks until lock acquired""" 22 23 # block until lock released then acquire lock 24 self.threadCondition.acquire() 25 26 # while all buffers are full, release lock and block 27 while self.occupiedBufferCount == len( self.buffer ): 28 print "All buffers full. %s waits." % \ 29 threading.currentThread().getName() 30 self.threadCondition.wait() 31 32 # (there is an empty buffer, lock has been re-acquired) 33 Three-element integer list that represents the circular bufferNumber of occupied buffersCurrent reading indexCurrent writing indexCondition variable protects access to circular bufferRelease lock and block while all buffers are full

42  2002 Prentice Hall. All rights reserved. Outline CircularBuffer.p y 34 # place value in writeLocation of buffer 35 # print string indicating produced value 36 self.buffer[ self.writeLocation ] = newNumber 37 print "%s writes %d " % \ 38 ( threading.currentThread().getName(), newNumber ), 39 40 # produced value, so increment number of occupied buffers 41 self.occupiedBufferCount += 1 42 43 # update writeLocation for future write operation 44 # add current state to output 45 self.writeLocation = ( self.writeLocation + 1 ) % \ 46 len( self.buffer ) 47 self.displayState() 48 49 self.threadCondition.notify() # wake up a waiting thread 50 self.threadCondition.release() # allow lock to be acquired 51 52 def get( self ): 53 """Get next buffer index value--blocks until lock acquired""" 54 55 # block until lock released then acquire lock 56 self.threadCondition.acquire() 57 58 # while all buffers are empty, release lock and block 59 while self.occupiedBufferCount == 0: 60 print "All buffers empty. %s waits." % \ 61 threading.currentThread().getName() 62 self.threadCondition.wait() 63 64 # (there is a full buffer, lock has been re-acquired) 65 Place value at write indexUpdate write index for future write operationsRelease lock and block while buffers are empty

43  2002 Prentice Hall. All rights reserved. Outline CircularBuffer.p y 66 # obtain value at current readLocation 67 # print string indicating consumed value 68 tempNumber = self.buffer[ self.readLocation ] 69 print "%s reads %d " % ( threading.currentThread().getName(), 70 tempNumber ), 71 72 # consumed value, so decrement number of occupied buffers 73 self.occupiedBufferCount -= 1 74 75 # update readLocation for future read operation 76 # add current state to output 77 self.readLocation = ( self.readLocation + 1 ) % \ 78 len( self.buffer ) 79 self.displayState() 80 81 self.threadCondition.notify() # wake up a waiting thread 82 self.threadCondition.release() # allow lock to be acquired 83 84 return tempNumber 85 86 def displayState( self ): 87 """Display current state""" 88 89 # display first line of state information 90 print "(buffers occupied: %d)" % self.occupiedBufferCount 91 print "buffers: ", 92 93 for item in self.buffer: 94 print " %d " % item, 95 96 # display second line of state information 97 print "\n ", 98 99 for item in self.buffer: 100 print "---- ", Obtain and print value at current read indexUpdate read index for future read operationsDisplay current circular buffer state

44  2002 Prentice Hall. All rights reserved. Outline CircularBuffer.p y 101 102 # display third line of state information 103 print "\n ", 104 105 for i in range( len( self.buffer ) ): 106 107 if ( i == self.writeLocation ) and \ 108 ( self.writeLocation == self.readLocation ): 109 print " WR ", 110 elif ( i == self.writeLocation ): 111 print " W ", 112 elif ( i == self.readLocation ): 113 print " R ", 114 else: 115 print " ", 116 117 print "\n"

45  2002 Prentice Hall. All rights reserved. 19.9 Semaphores Semaphore: variable that controls access to common resource or critical section Maintains a counter that specifies number of threads that can use the resource or enter the critical section simultaneously Counter decremented each time a thread acquires the semaphore When counter reaches zero, semaphore blocks other threads from accessing semaphore until it has been released by another thread

46  2002 Prentice Hall. All rights reserved. Outline fig19_14.py 1 # Figure 19.14: fig19_14.py 2 # Semaphore to control access to a critical section. 3 4 import threading 5 import random 6 import time 7 8 class SemaphoreThread( threading.Thread ): 9 """Class using semaphores""" 10 11 availableTables = [ "A", "B", "C", "D", "E" ] 12 13 def __init__( self, threadName, semaphore ): 14 """Initialize thread""" 15 16 threading.Thread.__init__( self, name = threadName ) 17 self.sleepTime = random.randrange( 1, 6 ) 18 19 # set the semaphore as a data attribute of the class 20 self.threadSemaphore = semaphore 21 22 def run( self ): 23 """Print message and release semaphore""" 24 25 # acquire the semaphore 26 self.threadSemaphore.acquire() 27 28 # remove a table from the list 29 table = SemaphoreThread.availableTables.pop() 30 print "%s entered; seated at table %s." % \ 31 ( self.getName(), table ), 32 print SemaphoreThread.availableTables 33 34 time.sleep( self.sleepTime ) # enjoy a meal 35 Class using semaphoresSet semaphore as a data attributeAcquire the semaphoreRemove a table from the listThread sleeps (i.e., customer enjoys a meal)

47  2002 Prentice Hall. All rights reserved. Outline fig19_14.py 36 # free a table 37 print " %s exiting; freeing table %s." % \ 38 ( self.getName(), table ), 39 SemaphoreThread.availableTables.append( table ) 40 print SemaphoreThread.availableTables 41 42 # release the semaphore after execution finishes 43 self.threadSemaphore.release() 44 45 threads = [] # list of threads 46 47 # semaphore allows five threads to enter critical section 48 threadSemaphore = threading.Semaphore( 49 len( SemaphoreThread.availableTables ) ) 50 51 # create ten threads 52 for i in range( 1, 11 ): 53 threads.append( SemaphoreThread( "thread" + str( i ), 54 threadSemaphore ) ) 55 56 # start each thread 57 for thread in threads: 58 thread.start() Free table by appending it to listRelease semaphore after critical section executes Create threading.Semaphore and set internal counter to five Start ten threads

48  2002 Prentice Hall. All rights reserved. Outline fig19_14.py thread1 entered; seated at table E. ['A', 'B', 'C', 'D'] thread2 entered; seated at table D. ['A', 'B', 'C'] thread3 entered; seated at table C. ['A', 'B'] thread4 entered; seated at table B. ['A'] thread5 entered; seated at table A. [] thread2 exiting; freeing table D. ['D'] thread6 entered; seated at table D. [] thread1 exiting; freeing table E. ['E'] thread7 entered; seated at table E. [] thread3 exiting; freeing table C. ['C'] thread8 entered; seated at table C. [] thread4 exiting; freeing table B. ['B'] thread9 entered; seated at table B. [] thread5 exiting; freeing table A. ['A'] thread10 entered; seated at table A. [] thread7 exiting; freeing table E. ['E'] thread8 exiting; freeing table C. ['E', 'C'] thread9 exiting; freeing table B. ['E', 'C', 'B'] thread10 exiting; freeing table A. ['E', 'C', 'B', 'A'] thread6 exiting; freeing table D. ['E', 'C', 'B', 'A', 'D']

49  2002 Prentice Hall. All rights reserved. 19.10 Events Module threading defines class Event, which is useful for thread communication Event objects have an internal, true or false flag One or more threads call the Event object’s wait method to block until the event occurs When the event occurs, the blocked thread or threads are awakened in the order that they arrived and resume execution

50  2002 Prentice Hall. All rights reserved. Outline fig19_15.py 1 # Fig. 19.15: fig19_15.py 2 # Event objects. 3 4 import threading 5 import random 6 import time 7 8 class VehicleThread( threading.Thread ): 9 """Class representing a motor vehicle at an intersection""" 10 11 def __init__( self, threadName, event ): 12 """Initializes thread""" 13 14 threading.Thread.__init__( self, name = threadName ) 15 16 # ensures that each vehicle waits for a green light 17 self.threadEvent = event 18 19 def run( self ): 20 """Vehicle waits unless/until light is green""" 21 22 # stagger arrival times 23 time.sleep( random.randrange( 1, 10 ) ) 24 25 # prints arrival time of car at intersection 26 print "%s arrived at %s" % \ 27 ( self.getName(), time.ctime( time.time() ) ) 28 29 # flag is false until light is green 30 self.threadEvent.wait() 31 32 # displays time that car departs intersection 33 print "%s passes through intersection at %s" % \ 34 ( self.getName(), time.ctime( time.time() ) ) 35 VehicleThread objects represent motor vehicle at an intersectionEach thread has Event object as data attribute Thread is in blocked state until light is green Displays message after Event flag becomes true

51  2002 Prentice Hall. All rights reserved. Outline fig19_15.py 36 greenLight = threading.Event() 37 vehicleThreads = [] 38 39 # creates and starts ten Vehicle threads 40 for i in range( 1, 11 ): 41 vehicleThreads.append( VehicleThread( "Vehicle" + str( i ), 42 greenLight ) ) 43 44 for vehicle in vehicleThreads: 45 vehicle.start() 46 47 while threading.activeCount() > 1: 48 49 # sets the Event's flag to false -- block all incoming vehicles 50 greenLight.clear() 51 print "RED LIGHT! at", time.ctime( time.time() ) 52 time.sleep( 3 ) 53 54 # sets the Event's flag to true -- awaken all waiting vehicles 55 print "GREEN LIGHT! at", time.ctime( time.time() ) 56 greenLight.set() 57 time.sleep( 1 ) Instantiate Event object Start eleven VehicleThread objectsSet Event object’s flag to falseSet Event object’s flag to true

52  2002 Prentice Hall. All rights reserved. Outline fig19_15.py RED LIGHT! at Fri Dec 21 18:10:44 2001 Vehicle7 arrived at Fri Dec 21 18:10:45 2001 Vehicle2 arrived at Fri Dec 21 18:10:46 2001 Vehicle8 arrived at Fri Dec 21 18:10:46 2001 GREEN LIGHT! at Fri Dec 21 18:10:47 2001 Vehicle7 passes through intersection at Fri Dec 21 18:10:47 2001 Vehicle2 passes through intersection at Fri Dec 21 18:10:47 2001 Vehicle8 passes through intersection at Fri Dec 21 18:10:47 2001 Vehicle1 arrived at Fri Dec 21 18:10:48 2001 Vehicle1 passes through intersection at Fri Dec 21 18:10:48 2001 Vehicle9 arrived at Fri Dec 21 18:10:48 2001 Vehicle9 passes through intersection at Fri Dec 21 18:10:48 2001 Vehicle10 arrived at Fri Dec 21 18:10:48 2001 Vehicle10 passes through intersection at Fri Dec 21 18:10:48 2001 RED LIGHT! at Fri Dec 21 18:10:48 2001 Vehicle4 arrived at Fri Dec 21 18:10:50 2001 Vehicle5 arrived at Fri Dec 21 18:10:50 2001 Vehicle6 arrived at Fri Dec 21 18:10:51 2001 GREEN LIGHT! at Fri Dec 21 18:10:51 2001 Vehicle4 passes through intersection at Fri Dec 21 18:10:51 2001 Vehicle5 passes through intersection at Fri Dec 21 18:10:51 2001 Vehicle6 passes through intersection at Fri Dec 21 18:10:51 2001 RED LIGHT! at Fri Dec 21 18:10:52 2001 Vehicle3 arrived at Fri Dec 21 18:10:53 2001 GREEN LIGHT! at Fri Dec 21 18:10:55 2001 Vehicle3 passes through intersection at Fri Dec 21 18:10:55 2001


Download ppt " 2002 Prentice Hall. All rights reserved. Chapter 19 - Multithreading Outline 19.1 Introduction 19.2 Thread States: Life Cycle of a Thread 19.3 threading.Thread."

Similar presentations


Ads by Google