[Tutor] Threads.... Unhandle my Exception you Feind! (fwd)

Daniel Yoo dyoo@hkn.eecs.berkeley.edu
Thu, 14 Jun 2001 12:57:19 -0700 (PDT)


On Thu, 14 Jun 2001 kromag@nsacom.net wrote:


> ----------------end dbwrong.py---------------
> <drumroll>
> 
> >pythonw -u dbwrong.py
> el vomito 2
> Unhandled exception in thread:
> Traceback (most recent call last):
>   File "dbwrong.py", line 17, in write
>     db.Execute("insert into data values(%f, '%s')" % inputtage)
> AttributeError: 'None' object has no attribute 'Execute'
> >Exit code: 0
> 
> 
> Thread it is! :-)

Ah ha!  Now I can make a good guess at what's happening.  Here's the
guess: when the main thread (the main program) gets to the end of the
program, it finishes.  However, the program still needs to wait until the
newly-spawned thread finishes.  That's ok so far.

The big problem is: what happens to all the variables created from the
main thread, after the thread dies?  In particular, what happens to our
'db' variable?  What I think is happening is that Python believes we won't
be needing 'db' anymore, so it sets it back to None.  Let's look at the
program again, and this theory might gain plausibility:


> engine=win32com.client.Dispatch("DAO.DBEngine.35")
> db=engine.OpenDatabase(r"windowsdesktopterror.mdb")
> if db==None:                 ## This was added since
> 	print 'el vomito 1'  ## last posting!
> 
> 
> ## Function write() writes a list to the database
> def write(inputtage):
> 	if db==None:
> 		print 'el vomito 2' ## As was this...
> 	db.Execute("insert into data values(%f, '%s')" % inputtage)
> 	return 'ok'
> 
> if __name__=='__main__':
> 	tik_tok=time.time()
> 	surprize=random.choice(['Hellbilly', 'Crunchy Tack', 'Feeble'])
> 	the_madness=(tik_tok, surprize)
> 	thread.start_new_thread(write,(the_madness,))

I'll pretend to be the Python system.  "We've just started the new thread.  
Hey, we're done with the main thread!  I'll be nice and clean up the
resources my user doesn't need.  Let's see... we don't need 'engine'
anymore.  Ok, let's toss that.  How about 'db'?  I don't see that anyone
needs it, since write() is in its own little black bock.  Ok, let's toss
that aside too!"  Of course, I could be really wrong about this, but this
is my best guess.

The fix is to convince Python that it really should keep 'db': let's
include it as another argument to the write() function.  Here's an edit of
your program:

###
import win32com.client
import random
import time
import string
import thread

## Function write() writes a list to the database
def write(db, inputtage):
	if db==None:
		print 'el vomito 2' ## As was this...
	db.Execute("insert into data values(%f, '%s')" % inputtage)
	return 'ok'

if __name__=='__main__':
	engine = win32com.client.Dispatch("DAO.DBEngine.35")
	db = engine.OpenDatabase(r"windowsdesktopterror.mdb")
	tik_tok = time.time()
	surprize = random.choice(['Hellbilly', 'Crunchy Tack', 'Feeble'])
	the_madness = (tik_tok, surprize)
	thread.start_new_thread(write,(db, the_madness))
###

The way that this works is that when the main thread is done, and when it
sees if 'db' can be recycled for its bits, the new thread can step in and
say "Gimme!", and maintain db for its own use.  It also avoids global
variables.

I'll cross my fingers about this one... *grin*

Good luck!