Unit 5
Python - Multithreaded Programming
Running several threads is similar to running several different programs concurrently, but with the following
benefits −
• Multiple threads within a process share the same data space with the main thread and can
therefore share information or communicate with each other more easily than if they were separate
processes.
• Threads sometimes called light-weight processes and they do not require much memory overhead;
they are cheaper than processes.
A thread has a beginning, an execution sequence, and a conclusion. It has an instruction pointer that keeps
track of where within its context it is currently running.
• It can be pre-empted (interrupted)
• It can temporarily be put on hold (also known as sleeping) while other threads are running - this is
called yielding.
Starting a New Thread
To spawn another thread, you need to call following method available in thread module −
thread.start_new_thread ( function, args[, kwargs] )
This method call enables a fast and efficient way to create new threads in both Linux and Windows.
The method call returns immediately and the child thread starts and calls function with the passed list
of args. When function returns, the thread terminates.
Here, args is a tuple of arguments; use an empty tuple to call function without passing any
arguments. kwargs is an optional dictionary of keyword arguments.
Example
#!/usr/bin/python
import thread
import time
# Define a function for the thread
def print_time( threadName, delay):
count = 0
while count < 5:
[Link](delay)
count += 1
print "%s: %s" % ( threadName, [Link]([Link]()) )
# Create two threads as follows
try:
thread.start_new_thread( print_time, ("Thread-1", 2, ) )
thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print "Error: unable to start thread"
while 1:
pass
When the above code is executed, it produces the following result –
Thread-1: Thu Jan 22 [Link] 2009
Thread-1: Thu Jan 22 [Link] 2009
Thread-2: Thu Jan 22 [Link] 2009
Thread-1: Thu Jan 22 [Link] 2009
Thread-2: Thu Jan 22 [Link] 2009
Thread-1: Thu Jan 22 [Link] 2009
Thread-1: Thu Jan 22 [Link] 2009
Thread-2: Thu Jan 22 [Link] 2009
Thread-2: Thu Jan 22 [Link] 2009
Thread-2: Thu Jan 22 [Link] 2009
Although it is very effective for low-level threading, but the thread module is very limited compared to the
newer threading module.
The Threading Module
The newer threading module included with Python 2.4 provides much more powerful, high-level support for
threads than the thread module discussed in the previous section.
The threading module exposes all the methods of the thread module and provides some additional methods
−
• [Link]() − Returns the number of thread objects that are active.
• [Link]() − Returns the number of thread objects in the caller's thread control.
• [Link]() − Returns a list of all thread objects that are currently active.
In addition to the methods, the threading module has the Thread class that implements threading. The
methods provided by the Thread class are as follows −
• run() − The run() method is the entry point for a thread.
• start() − The start() method starts a thread by calling the run method.
• join([time]) − The join() waits for threads to terminate.
• isAlive() − The isAlive() method checks whether a thread is still executing.
• getName() − The getName() method returns the name of a thread.
• setName() − The setName() method sets the name of a thread.
Creating Thread Using Threading Module
To implement a new thread using the threading module, you have to do the following −
• Define a new subclass of the Thread class.
• Override the __init__(self [,args]) method to add additional arguments.
• Then, override the run(self [,args]) method to implement what the thread should do when started.
Once you have created the new Thread subclass, you can create an instance of it and then start a new
thread by invoking the start(), which in turn calls run() method.
Example
#!/usr/bin/python
import threading
import time
exitFlag = 0
class myThread ([Link]):
def __init__(self, threadID, name, counter):
[Link].__init__(self)
[Link] = threadID
[Link] = name
[Link] = counter
def run(self):
print "Starting " + [Link]
print_time([Link], 5, [Link])
print "Exiting " + [Link]
def print_time(threadName, counter, delay):
while counter:
if exitFlag:
[Link]()
[Link](delay)
print "%s: %s" % (threadName, [Link]([Link]()))
counter -= 1
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
[Link]()
[Link]()
print "Exiting Main Thread"
When the above code is executed, it produces the following result −
Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 [Link] 2013
Thread-1: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Thread-1: Thu Mar 21 [Link] 2013
Thread-1: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Thread-1: Thu Mar 21 [Link] 2013
Exiting Thread-1
Thread-2: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Exiting Thread-2
Synchronizing Threads
The threading module provided with Python includes a simple-to-implement locking mechanism that allows
you to synchronize threads. A new lock is created by calling the Lock() method, which returns the new lock.
The acquire(blocking) method of the new lock object is used to force threads to run synchronously. The
optional blocking parameter enables you to control whether the thread waits to acquire the lock.
If blocking is set to 0, the thread returns immediately with a 0 value if the lock cannot be acquired and with a
1 if the lock was acquired. If blocking is set to 1, the thread blocks and wait for the lock to be released.
The release() method of the new lock object is used to release the lock when it is no longer required.
Example
#!/usr/bin/python
import threading
import time
class myThread ([Link]):
def __init__(self, threadID, name, counter):
[Link].__init__(self)
[Link] = threadID
[Link] = name
[Link] = counter
def run(self):
print "Starting " + [Link]
# Get lock to synchronize threads
[Link]()
print_time([Link], [Link], 3)
# Free lock to release next thread
[Link]()
def print_time(threadName, delay, counter):
while counter:
[Link](delay)
print "%s: %s" % (threadName, [Link]([Link]()))
counter -= 1
threadLock = [Link]()
threads = []
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
[Link]()
[Link]()
# Add threads to thread list
[Link](thread1)
[Link](thread2)
# Wait for all threads to complete
for t in threads:
[Link]()
print "Exiting Main Thread"
When the above code is executed, it produces the following result −
Starting Thread-1
Starting Thread-2
Thread-1: Thu Mar 21 [Link] 2013
Thread-1: Thu Mar 21 [Link] 2013
Thread-1: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Thread-2: Thu Mar 21 [Link] 2013
Exiting Main Thread
Multithreaded Priority Queue
The Queue module allows you to create a new queue object that can hold a specific number of items.
There are following methods to control the Queue −
• get() − The get() removes and returns an item from the queue.
• put() − The put adds item to a queue.
• qsize() − The qsize() returns the number of items that are currently in the queue.
• empty() − The empty( ) returns True if queue is empty; otherwise, False.
• full() − the full() returns True if queue is full; otherwise, False.
Example
#!/usr/bin/python
import Queue
import threading
import time
exitFlag = 0
class myThread ([Link]):
def __init__(self, threadID, name, q):
[Link].__init__(self)
[Link] = threadID
[Link] = name
self.q = q
def run(self):
print "Starting " + [Link]
process_data([Link], self.q)
print "Exiting " + [Link]
def process_data(threadName, q):
while not exitFlag:
[Link]()
if not [Link]():
data = [Link]()
[Link]()
print "%s processing %s" % (threadName, data)
else:
[Link]()
[Link](1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = [Link]()
workQueue = [Link](10)
threads = []
threadID = 1
# Create new threads
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
[Link]()
[Link](thread)
threadID += 1
# Fill the queue
[Link]()
for word in nameList:
[Link](word)
[Link]()
# Wait for queue to empty
while not [Link]():
pass
# Notify threads it's time to exit
exitFlag = 1
# Wait for all threads to complete
for t in threads:
[Link]()
print "Exiting Main Thread"
When the above code is executed, it produces the following result −
Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread
Python - GUI Programming (Tkinter)
Python provides various options for developing graphical user interfaces (GUIs). Most important are listed
below.
• Tkinter − Tkinter is the Python interface to the Tk GUI toolkit shipped with Python. We would look
this option in this chapter.
• wxPython − This is an open-source Python interface for wxWindows [Link]
• JPython − JPython is a Python port for Java which gives Python scripts seamless access to Java
class libraries on the local machine [Link]
Tkinter Programming
Tkinter is the standard GUI library for Python. Python when combined with Tkinter provides a fast and easy
way to create GUI applications. Tkinter provides a powerful object-oriented interface to the Tk GUI toolkit.
Creating a GUI application using Tkinter is an easy task. All you need to do is perform the following steps −
• Import the Tkinter module.
• Create the GUI application main window.
• Add one or more of the above-mentioned widgets to the GUI application.
• Enter the main event loop to take action against each event triggered by the user.
Example
#!/usr/bin/python
import Tkinter
top = [Link]()
# Code to add widgets will go here...
[Link]()
This would create a following window −
Tkinter Widgets
Tkinter provides various controls, such as buttons, labels and text boxes used in a GUI application. These
controls are commonly called widgets.
There are currently 15 types of widgets in Tkinter. We present these widgets as well as a brief description in
the following table −
[Link]. Operator & Description
1 Button
The Button widget is used to display buttons in your application.
2 Canvas
The Canvas widget is used to draw shapes, such as lines, ovals, polygons and rectangles, in your
application.
3 Checkbutton
The Checkbutton widget is used to display a number of options as checkboxes. The user can
select multiple options at a time.
4 Entry
The Entry widget is used to display a single-line text field for accepting values from a user.
5 Frame
The Frame widget is used as a container widget to organize other widgets.
6 Label
The Label widget is used to provide a single-line caption for other widgets. It can also contain
images.
7 Listbox
The Listbox widget is used to provide a list of options to a user.
8 Menubutton
The Menubutton widget is used to display menus in your application.
9 Menu
The Menu widget is used to provide various commands to a user. These commands are contained
inside Menubutton.
10 Message
The Message widget is used to display multiline text fields for accepting values from a user.
11 Radiobutton
The Radiobutton widget is used to display a number of options as radio buttons. The user can
select only one option at a time.
12 Scale
The Scale widget is used to provide a slider widget.
13 Scrollbar
The Scrollbar widget is used to add scrolling capability to various widgets, such as list boxes.
14 Text
The Text widget is used to display text in multiple lines.
15 Toplevel
The Toplevel widget is used to provide a separate window container.
16 Spinbox
The Spinbox widget is a variant of the standard Tkinter Entry widget, which can be used to select
from a fixed number of values.
17 PanedWindow
A PanedWindow is a container widget that may contain any number of panes, arranged
horizontally or vertically.
18 LabelFrame
A labelframe is a simple container widget. Its primary purpose is to act as a spacer or container for
complex window layouts.
19 tkMessageBox
This module is used to display message boxes in your applications.
Standard attributes
Some standard attributes are following:
• Dimensions
• Colors
• Fonts
• Anchors
• Relief styles
• Bitmaps
• Cursors
Geometry Management
All Tkinter widgets have access to specific geometry management methods, which have the purpose of
organizing widgets throughout the parent widget area. Tkinter exposes the following geometry manager
classes: pack, grid, and place.
• The pack() Method − This geometry manager organizes widgets in blocks before placing them in
the parent widget.
• The grid() Method − This geometry manager organizes widgets in a table-like structure in the
parent widget.
• The place() Method − This geometry manager organizes widgets by placing them in a specific
position in the parent widget.