[Tutor] Threads.... More Despair....

Daniel Yoo dyoo@hkn.eecs.berkeley.edu
Mon, 11 Jun 2001 18:25:28 -0700 (PDT)


On Mon, 11 Jun 2001 kromag@nsacom.net wrote:

> The following pathetic script attempts to summon up a thread, write to
> a database and exit:

Ok, let's take a look.


> import win32com.client
> import random
> import time
> import string
> import thread
> 
> engine=win32com.client.Dispatch("DAO.DBEngine.35")
> db=engine.OpenDatabase("\windows\desktop\terror.mdb")
> 
> 
> ## Function write() writes a list to the database
> def write(inputtage):
> 	time=inputtage[0]
> 	data_string=inputtage[1]
> 	db.Execute("insert into data values(%f, '%s')" %(time, data_string))
> 	return 'ok'
> 
> tik_tok=time.time()
> surprize=random.choice(['Hellbilly', 'Crunchy Tack', 'Feeble'])
> the_madness=(tik_tok, surprize)

Looks ok so far.


> thread.start_new_thread(write(the_madness))

There's a small problem here; the problem is that the 'write(the_madness)'
part of this line is getting called too quickly.  What I mean is that, for
every command that is made of compound pieces, Python will execute the
inner stuff first, and then pass the results off to the outer
'thread.start_new_thread( results of "write(the_madness)" )' stuff.  The
result is that thread.start_new_thread is only getting one thing, and that
thing isn't something it can work with.  This explains the error:


> Traceback (most recent call last):
>   File "dbwrite.py", line 21, in ?
>     thread.start_new_thread(write(the_madness))
> TypeError: start_new_thread requires at least 2 arguments; 1 given

The quickest way to fix this is the following line:

    thread.start_new_thread(write, (the_madness,))

which tells Python "Ok, we want to start a new thread.  When it starts up,
it should execute 'write', with 'the_madness' as it's first
argument."  The really tricky part is the last part:

    (the_madness,)

because if we don't have that comma, Python won't be able to figure out
that 'the_madness' should fit into inputtage.


> Fair enough. I looked again at my spanking new copy of "Python
> Standard Library" and noticed that in the example
> 'start_new_thread(worker, ())'. In the example, worker() does not
> accept an argument. Hrm.

Yes, in that particular case, worker doesn't take any arguments, so the
second thing we give start_new_thread turns out to be an empty tuple.  
But in your case, you need to send off your write() function the_madness
as the first (and only) argument.


With this in mind, the documentation on thread.start_new_thread() might
make more sense now:

"""
start_new_thread (function, args[, kwargs])

Start a new thread. The thread executes the function function with the
argument list args (which must be a tuple)...
"""


> for my troubles. Since I don't have a clue what is going on this was
> not a big surprize! :-)

You're getting closer.  *grin*



For reference, here's another example of a threaded program:

###
import thread
import time

def fallingBridge(name, delay):
    print "The", name, "bridge is falling down..."
    time.sleep(delay)
    print "The", name, "bridge fell down!"


if __name__ == '__main__':
    bridges = ['london', 'san mateo', 'golden gate']
    delays = [1, 2, 3]
    for b, d in zip(bridges, delays):
        thread.start_new_thread(fallingBridge, (b, d))
    print "All done!"
###

And here it is in action:

###
All done!
>>> The golden gate bridge is falling down...
The san mateo bridge is falling down...
The london bridge is falling down...
The london bridge fell down!
The san mateo bridge fell down!
The golden gate bridge fell down!
###

Hmmm... I knew I forgot to tell my main thread to wait until all my
threads were done.  It's saying "All done!" a bit too quickly, and that's
what motivates the need for more control over our threads.  The
'threading' module allows us to do this to our Threads with join(), but
that's for another message.  *grin*

Good luck!