promlems with threading and print

A

Andreas Grommek

Hi Newsgroup,

I'm new to python and I am familiarizing myself with threads (haven't done any threading in any
other language before...). I was playing around and discovered some weird behavior. Here is my code:

import threading
from time import sleep
from random import random
import sys

class MyThread(threading.Thread):

def __init__(self, t, s):
self.threadmarker = t
self.sleeptime = s
threading.Thread.__init__(self)

def run(self):
print("Tread", self.threadmarker, "is going to sleep for a while...")
sys.stdout.flush() #flush I/O
sleep(self.sleeptime) #go to sleep
print("Tread", self.threadmarker, "is waking up and terminating")

a = 1
b = 20
for n in range(a, b):
x = MyThread(n,random()*10.0)
x.start()


This should create some threads which print messages, go to sleep for a random amount of time (max
10 seconds) and return with a message. When I run the code I get something like this (always different):

Tread 1 is going to sleep for a while...
Tread 2 is going to sleep for a while...
Tread 3 is going to sleep for a while...
Tread 4 is going to sleep for a while...
Tread 5 is going to sleep for a while...
Tread 6 is going to sleep for a while...
Tread 6 is going to sleep for a while...
Tread 7 is going to sleep for a while...
Tread 7 is going to sleep for a while...
Tread 7 is going to sleep for a while...
Tread 8 is going to sleep for a while...
(...)

Some "going to sleep" messages appear more than once. If I increase the number of thread the problem
gets worse and threads are even started out of order (but this alone would not worry me...).

Are some threads startet more than once or is this an issue with print? What else can I do in
addition to sys.stdout.flush() after the first print statement? Are print and sleep thread-safe? Or
is this a bug (I use python 3.1)

Any hints and help for an newbie would be appreciated.

Thanks,
Andi
 
P

Piet van Oostrum

Andreas Grommek said:
AG> Hi Newsgroup,
AG> I'm new to python and I am familiarizing myself with threads
AG> (haven't done any threading in any other language before...). I was
AG> playing around and discovered some weird behavior. Here is my code:

When you start programming with threads you should familiarize yourself
with (or better: study) the subject of parallel programming. Without
that you will make hard to find and debug errors. Fortunately this one
you did find. Many of these have to do with 'shared resources', i.e.
resources (like objects) that are used in more than one thread at the
same time, while at least one thread modifies it/them.

For a start read this: http://effbot.org/zone/thread-synchronization.htm
and then read some more elaborate literature.
AG> import threading
AG> from time import sleep
AG> from random import random
AG> import sys
AG> class MyThread(threading.Thread):
AG> def __init__(self, t, s):
AG> self.threadmarker = t
AG> self.sleeptime = s
AG> threading.Thread.__init__(self)
AG> def run(self):
AG> print("Tread", self.threadmarker, "is going to sleep for a while...")
AG> sys.stdout.flush() #flush I/O
AG> sleep(self.sleeptime) #go to sleep
AG> print("Tread", self.threadmarker, "is waking up and terminating")

What happens here is that stdout is a shared resource that you are
modifying in different threads. So you have to protect it.
AG> a = 1
AG> b = 20
AG> for n in range(a, b):
AG> x = MyThread(n,random()*10.0)
AG> x.start()

AG> This should create some threads which print messages, go to sleep for a random amount of time (max
AG> 10 seconds) and return with a message. When I run the code I get something like this (always different):

You can get even weirder stuff, like:

('Tread', 1, 'is going to sleep for a while...')
('Tread', 2, 'is going to sleep for a while...')
('Tread', 3, 'is going to sleep for a while...')
('Tread', 4, 'is going to sleep for a while...')
('Tread', 5, 'is going to sleep for a while...')
('Tread', 6, 'is going to sleep for a while...')
('Tread', 7, 'is going to sleep for a while...')
('Tread', 8('Tread', , 'is going to sleep for a while...'9, )'is going to sleep for a while...'
('Tread'),
10, 'is going to sleep for a while...')
('Tread'('Tread', 12, 'is going to sleep for a while...')
, 11, 'is going to sleep for a while...')
('Tread', 13, 'is going to sleep for a while...')
('Tread', 14, 'is going to sleep for a while...')
('Tread', 15, 'is going to sleep for a while...')
('Tread', 16, 'is going to sleep for a while...')
('Tread', 17, 'is going to sleep for a while...')
('Tread'('Tread', 19, 'is going to sleep for a while...')
, 18, 'is going to sleep for a while...')
('Tread', 10, 'is waking up and terminating')
....

Here is a solution using locks (and at the same time I corrected
Tread->Thread

class MyThread(threading.Thread):

def __init__(self, t, s, lock):
self.lock = lock
self.threadmarker = t
self.sleeptime = s
threading.Thread.__init__(self)

def run(self):
with lock:
print("Thread", self.threadmarker, "is going to sleep for a while...")
sys.stdout.flush() #flush I/O
sleep(self.sleeptime) #go to sleep
with lock:
print("Thread", self.threadmarker, "is waking up and terminating")

a = 1
b = 20
lock = threading.Lock()
for n in range(a, b):
x = MyThread(n,random()*10.0, lock)
x.start()

If you have an older version of Python you have to replace
with lock:
statement
by
lock.acquire()
try:
statement
finally:
lock.release()

or if you want to risk deadlocks:

lock.acquire()
statement
lock.release()
 
P

Piet van Oostrum

Piet van Oostrum said:
PvO> def run(self):
PvO> with lock:

All the 'with lock:' lines should have been 'with self.lock:' but as
lock is also a global variable, it did work. Of course you can decide to
use only the global variable and get rid of the self.lock altogether. I
am not very fond of global variables myself, however, that's why I used
the self.lock.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top