An Introduction to Thread Programming

Sunday, August 10, 2008


This writing explains the basics of thread programming, for a beginner, the concept of thread programming is often intimidating with the complexities involved in it, therefore its very important to get the basics right. This article explains the basics of threads, creating multiple threads of control from the main program using a simplified syntax and also some slightly advanced concepts like acquiring and releasing locks.

As obvious I have choses python programming language to illustrate some of the thread programming concepts because of the ease in which one can create and invoke multiple threads. For a beginners tutorial on python visit here.

I will list three simple programs to illustrate the thread concept, which were described below.

1. Invoke a simple thread from main program which will print some numbers in an iteration, then interrupt the main program when done.

2. Create multiple threads from main which will invoke a function which will increment the thread count, sleeps for a second and prints the incremented value, however the threads don't use locks, as a result it ends up printing a wrong value (not the resulting value after it incremented).

3. Improve the limitations in listing 2 using locks.

1. Creating a thread in python

The simple way to start a thread in python is to invoke a function as a thread using the thread.start_new_thread() call which takes the function name as an argument and a tuple for the function parameters.

The thread function run_thread takes three arguments, the thread name, a count used for printing numbers in an iteration and a sleep time between the print statements. Note that before the thread exits, it interrupts the main using thread.interrupt_main() method which throws a KeyboardInterrupt which the main program handles to signal the end of the thread execution.

Listing 1: simple_thread.py
#
# Introduction to thread programming in python
# simple_thread.py
# Author: S.Prasanna
#

import thread
import threading
import time

def run_thread (threadname, count, sleeptime):
"""This is the thread function to be invoked."""

print "I am thread", threadname
for i in range (1, count + 1):
print "%s: count = %s" % (threadname, i)
time.sleep(sleeptime)

thread.interrupt_main()

if __name__ == "__main__":

thread.start_new_thread(run_thread, ("Thread1", 5, 1))

try:
while 1:
pass
except:
print "Thread1 exited...."
Output:

I am thread Thread1
Thread1: count = 1
Thread1: count = 2
Thread1: count = 3
Thread1: count = 4
Thread1: count = 5
Thread1 exited....

2. Creating multiple threads

In this program, the main creates four threads, each one incrementing a global thread count variable 'threadcount', then sleeps for a second and prints the incremented variable. Since the threads are context switched when they sleep, the other threads increments the global threadcount when it executes and when the previous thread prints the count when it executes again, it results in a wrong value being printed i.e the thread doesn't print its incremented value.

Listing 2: pythreads.py
#
# Invoking multiple threads from python without locking mechanism
# pythreads.py
# Author: S.Prasanna
#

import thread
import threading
import time

def run_thread (threadname, sleeptime):
"""This is the thread function to be invoked."""

global threadcount, activethreads

print "%s: Current value of threadcount %s" % (threadname, threadcount)
print "%s incrementing threadcount" % (threadname)
threadcount = threadcount + 1
time.sleep(sleeptime)
print "Value of threadcount after incremented by %s = %s" % (threadname, threadcount)
activethreads = activethreads - 1
print "%s exiting...." % (threadname)

if __name__ == "__main__":

threadcount=0
activethreads = 4

thread.start_new_thread(run_thread, ("Thread1", 1))
thread.start_new_thread(run_thread, ("Thread2", 1))
thread.start_new_thread(run_thread, ("Thread3", 1))
thread.start_new_thread(run_thread, ("Thread4", 1))

while activethreads > 0:
pass
Output:

Thread1: Current value of threadcount 0
Thread1 incrementing threadcount
Thread2: Current value of threadcount 1
Thread2 incrementing threadcount
Thread3: Current value of threadcount 2
Thread3 incrementing threadcount
Thread4: Current value of threadcount 3
Thread4 incrementing threadcount
Value of threadcount after incremented by Thread1 = 4
Thread1 exiting....
Value of threadcount after incremented by Thread2 = 4
Thread2 exiting....
Value of threadcount after incremented by Thread3 = 4
Thread3 exiting....
Value of threadcount after incremented by Thread4 = 4
Thread4 exiting....

The threads before exiting decrements the activethreads count and when all threads exit, the main exits. A more stable version of listing 2 using locks is given below.

3. Creating multiple threads with locks

The thread.allocate_lock() function returns a lock object and a thread calls acquire() and release() methods on the lock object to to acquire and release locks respectively. Now when each thread executes the run_thread function, it acquires the lock, increments thread count, sleeps, prints the incremented value and decrements the active thread count before releasing the lock, now the threadcount value it prints is the value incremented by that thread.

Listing 3: pythreads_lock.py
#
# Invoking multiple threads from python with locks
# pythreads_lock.py
# Author: S.Prasanna
#

import thread
import threading
import time

def run_thread (threadname, sleeptime):
"""This is the thread function to be invoked."""

global threadcount, activethreads, threadlock

threadlock.acquire()

print "%s: Current value of threadcount %s" % (threadname, threadcount)
print "%s incrementing threadcount" % (threadname)
threadcount = threadcount + 1
time.sleep(sleeptime)
print "Value of threadcount after incremented by %s = %s" % (threadname, threadcount)
activethreads = activethreads - 1
print "%s exiting...." % (threadname)

threadlock.release()

if __name__ == "__main__":

threadcount=0
activethreads = 4
threadlock = thread.allocate_lock()

thread.start_new_thread(run_thread, ("Thread1", 1))
thread.start_new_thread(run_thread, ("Thread2", 1))
thread.start_new_thread(run_thread, ("Thread3", 1))
thread.start_new_thread(run_thread, ("Thread4", 1))

while activethreads > 0:
pass
Output:

Thread1: Current value of threadcount 0
Thread1 incrementing threadcount
Value of threadcount after incremented by Thread1 = 1
Thread1 exiting....
Thread2: Current value of threadcount 1
Thread2 incrementing threadcount
Value of threadcount after incremented by Thread2 = 2
Thread2 exiting....
Thread3: Current value of threadcount 2
Thread3 incrementing threadcount
Value of threadcount after incremented by Thread3 = 3
Thread3 exiting....
Thread4: Current value of threadcount 3
Thread4 incrementing threadcount
Value of threadcount after incremented by Thread4 = 4
Thread4 exiting....

24 comments:

Chris Pearce said...

A more elegant way to detect the end of child threads is for the main thread to join() the child threads.

Prasanna Seshadri said...

Yes Chris, you are right using join() is the right way of doing it (that involves creating the Thread object and calling those methods), but I just want to keep the code simple using thread.start_new_thread() and the thread module doesn't have a join method.

stargaming said...

Why do you import threading at all?

Prasanna Seshadri said...

Hi,

I just want to invoke threads using thread.start_new_thread() to keep it simple, even though threading has a private method threading._start_new_thread, I thought it would be better off to call the method from thread module.

I am also planning to write more about threading module, Thread objects and its practical applications in future, this is just an introduction.

Anonymous said...

If you're using Python and want to use a thread-type setup, you might want to look into the Stackless variant. (http://www.stackless.com/)

It uses a more lightweight system where you can share execution through 'tasklets'. It's used by the MMO game "EVE Online" for their game servers. I've been learning it and hoping to use it for my own game project.

Prasanna Seshadri said...

Yes I came to know about stackless python sometime back, thanks for pointing it out, I will look deep into it as that may be an interesting solution as well.

Good that Python offers a lot many frameworks & tools which makes life easy for coders.

AM said...

What about the Global Interpreter Lock? A discussion of Python threading is incomplete if it fails to mention that Python threads do not execute concurrently and this do not take advantage of multicore processors.

Tragically.

Prasanna Seshadri said...

Yes, I should have mentioned about GIL (many people had similar opinion about that too when it comes to python), but this is just a basic introduction to threads, will take it up when I do something advanced, using the threading module.

Fabian K. said...

Nice How-To. Please post more about this subject, especially about the 'threading' module and thread communication.

Prasanna Seshadri said...

Thanks Fabian, a writeup on threading is round the corner, will publish it when it's complete.

Anonymous said...

Hi Im deepak.from India
I have a problem with a client -server code in c++.In program Client tries to communicate to the server by sending a TCP packet.The packet was sent sucessfully..But im not getting it in the other end .Surprisingly when i sent any other packet (may be of same client or other),i can get the packet that was sent before at the server...
I think its a coding bug....I couldnt trace it???
Can u help me out????

Prasanna Seshadri said...

Hi Deepak,

The possible reasons for that may be that the packet (in the form of string) may not be terminated with a newline or the buffer may not be flushed, try to add a newline at the end of the packet so that it will be flushed out.

I don't know exactly what you are doing, but check out my socket programming tutorial in C which may help you track if your sequence was right, do look here for the TCP Server/Client socket code in C.

http://www.prasannatech.net/2008/07/socket-programming-tutorial.html

Let me know if this helps.

php application development said...

Nice post on thread programming, got my doubts cleared... thanks...

Prasanna Seshadri said...

Thanks, Glad that you got your doubts cleared through this article.

Anonymous said...

thanks mr prasanna for giving simple tutorial on python threads and pgms provided here are handy for lazy coders like me-coimbatore boy

Anonymous said...

Using thread.interrupt_main() usually totally freezes my application, even if in sometimes it can also work (same conditions, same code, certainly not same timings...). There is no lock or semaphore in the child thread causing this issue

does anobody know in which case this can happen ? nothing is said about this in the python doc. I guess the main thread is doing something wrong (well, not fine to accept the exception maybe ?), but since it is not locked or waiting for the child process involved, I have really no idea...

Sam said...

Thank you very much for well-explained, easy to understand code.

sh said...

hi, what is the java command equivalent to System() command in c,
need a code to play mp3 file by calling a player.

equivalent of it in c is
system(mplayer song.mp3);

sh said...

getting an error while configuring Mplayer, please guide me to install Mplayer in fedora 13

suruchi said...

it is helpful if you send the chat code for c to my mail id.

Anonymous said...

just wanted to say thanks for the tutorial, found it very helpful!!! now off to read your post on vnc2swf :)

Prasanna Seshadri said...

Thanks!

Henrik Hellström said...

Just wanted to express my appreciation toward you for creating this. I managed to understand this in a matter of minutes, thanks for explaining it so efficiently and clearly!

bhaski said...

sir,am Bhaskar.
your article on python threads and sockets helped me a lot.thank you very much and I want you to write some more articles on cgi programming in python sir.
thank you


Copyright © 2008 Prasanna Seshadri, www.prasannatech.net, All Rights Reserved.
No part of the content or this site may be reproduced without prior written permission of the author.