>>>>> Andreas Grommek <a...@mozarellasalat.homelinux.net> (AG) wrote:

>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()

-- 
Piet van Oostrum <p...@cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: p...@vanoostrum.org
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to