Asynchronous Socket Programming using Non Blocking Sockets

Sunday, August 31, 2008

In my last article related socket programming, we have seen how to use select call to process multiple clients in an asynchronous way with a multi client server TCP/IP Chat program, now we will see how to implement a multi client server program in an asynchronous way using non blocking sockets. The main motivation for me in writing this one is till date I never found a complete implementation of a TCP Server handling multiple clients (accepting new connections and processing existing connections concurrently) using non blocking sockets. This code will work exactly like the way I implemented multiple client server communication using select, but it will use non blocking sockets, so there will be subtle difference in the way the server part is implemented.

Just to give a customary introduction of non blocking sockets, by default a socket is in a blocking mode, in other words when using recv call to read data from a socket, it will return only after some data is recieved, or it blocks till some data is is available in the client socket. In a typical client server scenario where many clients connect to the server, each client has to wait till the previous client socket is processed, resulting in inefficient use of system resources due to this block (idle time), therefore we need a solution where calls like recv, accept should not block, there comes non blocking sockets.

When a socket is set to non blocking mode, it will not block on calls like recv, when there is no data to be read on a socket, an exception will be thrown, the server can just ignore this socket exception and continue processing the next client and so on, thus multiple clients can be processed without any delay due to blocking.

The implementation language used is python, due to the simplicity in using the socket calls, I have used two threads, one to process existing TCP connections and another to accept new connections (for a basic introduction on using threads in python, read my article on thread programming here), the server socket is to non blocking mode to ensure that the accept call which is used to accept new connections will not block, as and when a client socket connects to the server, the client socket will also be set to non blocking mode, to ensure that the server will not block on recv call and thus can handle multiple clients without waiting for data to be read on a given client socket.

I have used locks to ensure that the threads used for accepting and processing client connections run into completion without context switch, though I have observed that without locks also the code would work similar, we will stick to the better programming approach. The only difference you will note here compared to my multi client server chat program using select call is that there would be a minor delay when a client connects to the server because the new connection would be accepted only when the thread which processes an existing connection will run to completion.

So here we go.

TCP/IP Chat Server:

1. Accepts connection from multiple clients
2. Use non blocking sockets to accept and process client connections.
3. Whenever a client connects, the server notifies all other connected clients of this new connection, in the same way the server notifies all when a client quits or that client connection is lost.
4. The server broadcasts data sent by a client to all other connected clients.

TCP/IP Chat Client:

1. Connects to the server and starts two threads, one to process received data and one for getting data input to be sent to other connected clients through the server.
2. When the client quits (using q or Q) or the server is suddenly down (handle the worst case scenario), the socket is closed and the process exits.
3. Whenever any thread closes the socket connection, it interrupts the main program using the thread.interrupt_main() call, then the main exits.

TCP/IP Non blocking Chat Server: tcpchatserver_nonblocking.py
#
# tcpchatserver_nonblocking.py
# TCP/IP Chat server
# Author: S.Prasanna
# The server accepts connection from multiple clients and
# broadcasts data sent by a client to all other clients
# which are online (connection active with server)
#

import socket
import select
import string
import thread
import sys, time
import traceback

def broadcast_data (sock, message):
"""Send broadcast message to all clients other than the
server socket and the client socket from which the data is received."""

global CONNECTION_LIST

for socket in CONNECTION_LIST:
if socket != sock:
socket.send(message)

def accept_connection():

global CONNECTION_LIST, RECV_BUFFER

try:

while 1:

threadlock.acquire()

try:

#print "waiting for accept"
sockfd, addr = server_socket.accept()
# Set socket to non-blocking mode
sockfd.setblocking(0)
CONNECTION_LIST.append(sockfd)
print "Client (%s, %s) connected" % addr
broadcast_data(sockfd, "Client (%s, %s) connected" % addr)

except:
pass

threadlock.release()

except:
#Handle the case when client program is terminated with Ctrl-C
#catch the exception and exit
pass

def process_connection():

global CONNECTION_LIST, RECV_BUFFER

try:

while 1:

#print "waiting for packet"
for sock in CONNECTION_LIST:

threadlock.acquire()

try:

data = sock.recv(RECV_BUFFER)

if data:

# The client sends some valid data, process it

if data == "q" or data == "Q":

broadcast_data(sock, "Client (%s, %s) quits" % sock.getpeername())
print "Client (%s, %s) quits" % sock.getpeername()
sock.close()
CONNECTION_LIST.remove(sock)

else:

broadcast_data(sock, data)

except:

#Exception thrown, get the error code and do cleanup actions
socket_errorcode = sys.exc_value[0]

if socket_errorcode == 10054:

# Connection reset by peer exception
# In Windows, sometimes when a TCP client program closes abruptly,
# or when you press Ctrl-C a "Connection reset by peer" exception will be thrown

broadcast_data(sock, "Client (%s, %s) quits" % sock.getpeername())
print "Client (%s, %s) quits" % sock.getpeername()
sock.close()
CONNECTION_LIST.remove(sock)

else:
# The socket is not ready for reading, which results in an exception,
# ignore this and pass on with the next client socket (without blocking)
# The exception you will see here is
# "The socket operation could not complete without blocking"
pass

threadlock.release()

except:
#Handle the case when server program is terminated with Ctrl-C
#catch the exception and exit
pass

if __name__ == "__main__":

# List to keep track of socket descriptors
CONNECTION_LIST=[]
RECV_BUFFER=4096 # Advisable to keep it as an exponent of 2

# Do basic steps for server like create, bind and listening on the socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1", 5000))
server_socket.listen(10)

# Set the server socket in non blocking mode, so that the server can accept connections
# without blocking
server_socket.setblocking(0)

threadlock = thread.allocate_lock()

print "TCP/IP Chat server process started."

#Invoke two threads to accept connections and handle eisting connections (client data)
thread.start_new_thread(accept_connection, ())
thread.start_new_thread(process_connection, ())

try:
while 1:
pass
except:
server_socket.close()

TCP/IP Chat Client: tcpchatclient_nonblocking.py
#
# tcpchatclient_nonblocking.py
# TCP/IP Chat client
# Author: S.Prasanna
# The client program connects to server and sends data to other connected
# clients through the server
#

import socket
import thread
import sys

HOST = '127.0.0.1' # The remote host
PORT = 5000 # The same port as used by the server
RECV_BUFFER=4096

def recv_data():
"Receive data from other clients connected to server"
while 1:
try:
recv_data = client_socket.recv(RECV_BUFFER)
except:
#Handle the case when server process terminates
print "Server closed connection, thread exiting."
thread.interrupt_main()
break
if not recv_data:
# Recv with no data, server closed connection
print "Server closed connection, thread exiting."
thread.interrupt_main()
break
else:
print "Received data: ", recv_data

def send_data():
"Send data from other clients connected to server"
while 1:
send_data = str(raw_input("Enter data to send (q or Q to quit):"))
if send_data == "q" or send_data == "Q":
client_socket.send(send_data)
thread.interrupt_main()
break
else:
client_socket.send(send_data)

if __name__ == "__main__":

print "*******TCP/IP Chat client program********"
print "Connecting to server at 127.0.0.1:5000"

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

print "Connected to server at 127.0.0.1:5000"

thread.start_new_thread(recv_data,())
thread.start_new_thread(send_data,())

try:
while 1:
continue
except:
print "Client program quits...."
client_socket.close()

How to Create a Flash Demo using Vnc2swf

Monday, August 25, 2008

Creating a flash demo is an effective way to make presentations, demonstrate working of a software, etc. But if you need to make eleventh hour preparation of flash demos, or in a hurry to create animated presentations, the following quick steps will be handy.

Vnc2swf is a light weight tool available for screen recording from any remote system, its a free tool with Windows as well as in Linux ports, often I got questions about the way to use it to create flash presentations from screen recordings, since I mostly for Solaris, I will give a quick step by step guide on how to use it to create your flash demo in minutes if you are new to this.

Vnc2swf comes in two flavours, one implemented in C and the other one in python (pyvnc2swf), the easiest way is to use the C version if you are working from Linux/Solaris environments.

1. Installing VNCServer and VNCViewer:

The well known free VNCServer/Viewer tool available for all platforms under GPL is RealVNC, which can be downloadable from here. The Windows/Linux installation is straightforward with the respective binary installers, after starting the RealVNC server (In Windows, Programs -> RealVNC -> VNC Server 4 user mode -> Run VNC Server), one can create a password for accessing the VNCServer (In Windows, Programs -> RealVNC -> VNC Server 4 user mode -> Confgure user-mode settings, select Authentication configuration), then from the remote system use VNCViewer (In Windows, Programs -> RealVNC -> VNC Viewer 4 ->. Run VNC Viewer) to access the server desktop.

For Solaris SPARC, RealVNC 4.1.2 Package is available, for Solaris x86 architecture, one can build RealVNC 4.1.2 from its source (or use one can download xVNC from sunfreeware.com here). In most recent Solaris distributions, VNCServer is available by default. Once VNCServer package is installed, one can start the VNCServer using the vncserver command, before that one can create a password for VNCServer access (Similar procedure may apply for Linux as well).

bash-3.00$ vncpasswd
Password:********
Verify:********
bash-3.00$

Once password is assigned, VNCServer can be started using the following command, the below is a sample output of VNCServer started on the vnchost on a Solaris box.

bash-3.00$ vncserver

New 'vnchost:1 (testuser)' desktop is vnchost:1

Starting applications specified in /home/testuser/.vnc/xstartup
Log file is /home/testuser/.vnc/vnchost:1.log

Once VNCServer setup is done, from the remote system one can use vncviewer command to access the remote desktop. The below sample output shows the successful execution of vncviewer command from remotehost to vnchost.

bash-3.00$ vncviewer vnchost:1

VNC Viewer Free Edition 4.1.2 for X - built May 15 2006 21:43:03
Copyright (C) 2002-2005 RealVNC Ltd.
See http://www.realvnc.com for information on VNC.
......
......
CConn: Throughput 20000 kbit/s - changing to hextile encoding
CConn: Throughput 20000 kbit/s - changing to full colour
CConn: Using pixel format depth 24 (32bpp) little-endian bgr888
CConn: Using hextile encoding

Once you get the remote desktop, then you are ready to use Vnc2swf.

Note: To enable or disable access control, one can use xhost - or xhost + command on the VNCServer.

2. Installing and running Vnc2swf (C Version):

This procedure applies to Solaris box, but can be applicable to other flavours of linux as well.

1. Download the source here.

2. Untar the source, cd into the source directory, execute ./configure, make, make install (Make sure you have a valid GCC Compiler installed, it may be found in /usr/sfw/bin, set PATH to make command as well, /usr/ccs/bin).

3. Now vnc2swf will be installed in the directory /usr/X11R6/bin (on a solaris box).

Now from any remote host, one can use Vnc2swf and connect to the VNC server host for screen recording, a sample output is shown below, here the recorded file is record.swf, it generates an HTML code (shown in the bottom), which can be invoked to run the recorded flash demo (After you get the remote desktop, press F9 to start/stop recording).

bash-3.00$ vnc2swf record.swf vnchost:1
vnc2swf version 0.5.0
Copyright (C) 2002-2005 Yusuke Shinyama <yusuke at cs dot nyu dot edu>
- Based on VNC viewer version 3.3.7
Copyright (C) 2002-2003 RealVNC Ltd.
Copyright (C) 1994-2000 AT&T Laboratories Cambridge.
See http://www.realvnc.com for information on VNC.
VNC server supports protocol version 3.8 (viewer 3.3)
Password:
VNC authentication succeeded
Desktop name "vnchost:1 (testuser)"
Connected to VNC server, using protocol version 3.3
VNC server default format:
16 bits per pixel.
Most significant byte first in each pixel.
True colour: max red 31 green 63 blue 31, shift red 11 green 5 blue 0
Using default colormap and visual, TrueColor, depth 24.
Using viewer's native pixel format:
32 bits per pixel.
Least significant byte first in each pixel.
True colour: max red 255 green 255 blue 255, shift red 0 green 8 blue 16
=== WriteInitMovie: Pid=5793, Opening file: "record.swf" for a movie size (1024, 768), frame rate 12.00...
=== WriteFinishMovie: 4175 bytes dumped into "record.swf".
<html><body>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="1024" height="768" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0">
<param name="movie" value="record.swf">
<param name="play" value="true">
<param name="loop" value="true">
<param name="quality" value="high">
<embed src="record.swf" width="1024" height="768" play="true" loop="true" quality="high" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>
</object>
</body>
</html>

3. Installing and running pyVnc2swf:

Running pyvnc2swf requires Python Imaging library or pygame module, for the sake of completeness, I will mention that too (using Python Imaging Library).

1. Download Python Imaging Library here.

2. Untar Python Imaging Library (Latest version is1.1.6).

3. Set PYTHONPATH to <Python_Imaging_Lib_Home>/Imaging-1.1.6/Imaging-1.1.6/PIL, this would ensure that the python imaging libraries would be used from this directory.

4. Download pyVnc2swf here.

5. Untar pyVnc2swf, cd to pyvnc2swf directory from the extracted directory.

6. Now run python vnc2swf.py, a GUI will be displayed where one can specify the server name, port on the VNCServer, the recorded output file, then click Start button to start recording.

7. From Windows, one can do the same thing by installing pyvnc2swf and launching it (Programs -> pyvnc2swf -> vnc2swf).

Its so simple to create flash demos, isn't it!

Online Syntax Highlighters on the web

Saturday, August 23, 2008

Syntax highlighting code is an important customization one should consider whenever it comes to publishing useful code on the web, something which my friends also recommended me to do when I posted code in this blog. But on the web when I searched for syntax highlighters I couldn't get what I exactly wanted with the keywords "Syntax Highlighting", "Python Syntax Highlighting", "Java Syntax Highlighting", etc, to be fair with Google its not that it didn't produce results, but not the generic results which I was expecting, but finally managed to break the ice with some sensible searches like "Online Syntax Highlighting", "Syntax Highlighters", etc.

One thing to note is that the more specific your keywords are, the more accurate the results will be, otherwise its really hard to get what you want, for example, see the difference between the searches "Syntax Highlighting", "Code Syntax Highlighting" and "Online Syntax Highlighting", clearly the third one will give you the result you want immediately. So its my duty to recommend and share the bits and pieces which I collected from web for syntax highlighting code, just to save you some search work, especially if you want to get the highlighted code, the way you want it to be. If you have time only to paste your source code and need to get HTML source/output for syntax highlighted code, then the below are my favorites (although its not complete, its enough for us to get the job done).

1. www.tohtml.com - The first useful result I got and the one I use mostly for my code highlighting purposes, the good thing I like is the default white background with very suitable colors for language keywords.

2. http://qbnz.com/highlighter/demo.php (Generic Syntax Highlighter, GeSHi) - Another powerful one loaded with as many customization options possible to the end user, a good thing, its downloadable too.

3. http://puzzleware.net/CodeHtmler/default.aspx - A very good, simple interface (yes, white rules) and downloadable.

4. http://www.chami.com/colorizer - A simple, yet effective one for good user experience while viewing code, downloadable.

5. Iris Syntax Highlighter: The best one I should say, supports from A - Z languages/tools from ANTLR parser generator to Zope DTML, great job, again downloadable.

6. quickhighlighter.com - A nice one with many options to customize the HTML source output, some good features are word wrap, option to add line numbers, etc.
In addition there is also a complete javascript Syntax Highlighter, published at code.google.com through which one can syntax highlight blogger code, though I haven't explored it, I will let you know once I get used to it, do let me know if you find anything useful, finally thanks for all the online syntax highlighters, you really make developers/bloggers job easy.

Java Swing Programming: Implementing a Buffered Scrollable Window

Sunday, August 17, 2008

In one of my applications related to Java Swing, I was implementing a buffered scrollable window which will output live logs from the application. But as the size of the logs grows to some extent, I just don't want to retain the obsolete or topmost old entries. In other words I want to implement a buffered scrollable window which will output lines till the buffer size is reached (the buffer size is specified as the maximum number of lines which can be displayed in the buffer), then the topmost entry in the window will be replaced by the second line, the second line by the third and so on to accommodate the new line at the bottom of the window.

This is something similar to a DOS or a UNIX terminal window in which after some lines were output, the oldest entries (those at the top of the command window) will be replaced by the new lines one by one.

The below code is an implementation of a buffered scrollable window using JFrame Swing component.

  1 /*
2 * BufferedScrollableWindow.java
3 * Author: S.Prasanna
4 * @version 1.00 08/12/2008
5 */

6
7 import javax.swing.JPanel;
8 import javax.swing.JTextArea;
9 import javax.swing.BorderFactory;
10 import javax.swing.JScrollPane;
11 import javax.swing.JFrame;
12 import javax.swing.BorderFactory;
13 import javax.swing.JDialog;
14 import java.awt.BorderLayout;
15 import java.awt.Dimension;
16
17 public class BufferedScrollableWindow {
18
19 final JTextArea statusmessageArea = new JTextArea();
20 final JScrollPane scroll = new JScrollPane(statusmessageArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
21 JFrame frame = new JFrame("This is a Buffered Scrollable Window");
22 int BUFFERSIZE = 10;
23 //BUFFERSIZE specifies maximum the no of lines in the window which can be printed
24 //before the topmost entry is replaced by the second line and all lines shifted
25 //one line above making way for the latest line to be printed out at the bottom of the
26 //window or buffer
27
28 BufferedScrollableWindow () {
29 statusmessageArea.setBorder(BorderFactory.createEtchedBorder());
30 statusmessageArea.setBorder(BorderFactory.createEtchedBorder());
31 statusmessageArea.setWrapStyleWord(true);
32
33 scroll.getViewport().setPreferredSize(new Dimension(400, 400));
34
35 frame.getContentPane().setLayout(new BorderLayout());
36 frame.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
37 frame.getContentPane().add(scroll, BorderLayout.CENTER);
38 frame.pack();
39 frame.setLocationRelativeTo(null);
40 frame.setVisible(true);
41 }
42
43 public void writeIndexStatusLine(String status) {
44
45 //When the line count in the text window > size of the buffer, replace the first line in buffer
46 //to give way to the last line, all lines in buffer shift one line up
47 if (statusmessageArea.getLineCount() > BUFFERSIZE) {
48 try {
49 statusmessageArea.replaceRange(null, statusmessageArea.getLineStartOffset(0),
statusmessageArea.getLineEndOffset(0));
50 } catch (Exception e) {
51 statusmessageArea.append("An exception occured in replacing the topmost entry in the buffer");
52 e.printStackTrace();
53 return;
54 }
55 }
56
57 statusmessageArea.append(status + "\n");
58
59 //Update the text window with the latest line to be printed
60 try {
61 statusmessageArea.setCaretPosition(statusmessageArea.getLineEndOffset(
statusmessageArea.getLineCount() - 1));
62 statusmessageArea.repaint();
63 } catch (Exception e1) {
64 statusmessageArea.append("An exception occured writing lines to buffer");
65 e1.printStackTrace();
66 }
67 }
68
69 public static void main(String[] args) throws Exception {
70
71 BufferedScrollableWindow BW = new BufferedScrollableWindow();
72
73 for (int i = 1; i<=50; i++) {
74 BW.writeIndexStatusLine("This is line " + i);
75 Thread.sleep(1000);
76 }
77
78 }
79 }
80
The working of the code is pretty cimple, a JScrollPane inside a JFrame displays a JTextArea component with horizontal and vertical scrollbars.

The two lines which does the trick were as follows.

Line 61: statusmessageArea.setCaretPosition(statusmessageArea.getLineEndOffset(statusmessageArea.getLineCount() - 1));

The setCaretPosition() method of JTextArea sets the position where the text will be appended, in our case this is set to the last line of the buffer so that a new line will be added to the bottom of the buffer.

Line 49: statusmessageArea.replaceRange(null, statusmessageArea.getLineStartOffset(0), statusmessageArea.getLineEndOffset(0));

The replaceRange() function of JTextArea replaces text from the indicated start to end position with the new text specified, if the specified text is null, the text between the start and end position is deleted, in our case when the number of lines exceeds the buffer size (i.e the maximum number of lines in the buffer), then the first line is deleted, the start and end position of the first line is fetched using statusmessageArea.getLineStartOffset(0) and statusmessageArea.getLineEndOffset(0) methods respectively.

In the below outputs, 50 lines are printed and we will look at cases where the buffer size is 10 and 40 lines respectively.

Output 1 and 2:

In the case the BUFFERSIZE = 10, the first ten lines are printed (Output 1) , when the 11th line is printed, line 1 in the top is replaced by line 2 and so on which is shown in the Output 2.






















Output 3 and 4:
In the case the BUFFERSIZE = 40, the scrollbar comes into picture since the number of lines is greater than the dimension of the window, once 50 lines are printed (bottom scroll, Output 3), the top 10 lines were replaced in the buffer (top scroll, Output 4).





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....


Copyright © 2016 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.