Mailing List Archive

New to threading. Right idea???
I need some advise. Am I on the right track?

The code below dose not work as I would expect. If a thread is an
idependant path of execution should not the objects created on those paths
and imported on those paths be separate entities?

I need to load the same dll more that once. I want to avoid mucking with or
renaming files if it can be avoided. Gordon McMillan sugested possibly
using threads in a post on 4/20/99. Am I thinking this though properly?
The same library is being loaded on separate threads. When a thread is
spawned it gets its own copy of the interpreter state(yes?). But the
library for objects returned for separate threads is the same. Should not
each get its own?

One of the functions in the dll is EXPENSIVE. It's not mine and I doubt
they will rework it so I have to live with it. the EXPENSIVE function must
be called at the begining and ties all activity in the dll to a specific
directory. If you want to change directories you must call unexpensive then
EXPENSIVE again with the new directory as an argument. If the dll is loaded
and EXPENSIVE has been called sucessive calls to EXPENSIVE return FALSE.

I experimented with creating a copy of the dll with a diferent name and
loading it. This worked. I could call EXPENSIVE for the dll and the
copy_of_dll and both succeed.

Back to threads. First tryed using the windll module, but it caches the dll
in a module level variable so I didn't see that working so I tryed the
example below and it still doesn't work.

Any ideas, or a swift kick in the right direction is greatly appreciated.

Karl Putland
kperacles@geocities.com

***Begin Example***

Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> class GMdll:
def __init__(self):
import calldll
self.calldll=calldll
self.handle=self.calldll.load_library('GM4S32.DLL')
self.h_load = self.calldll.get_proc_address(self.handle, "GMW_LoadBDE")
self.h_unload=self.calldll.get_proc_address(self.handle, "GMW_UnloadBDE")
def load(self):
from windll import cstring
s,g,c,u,p = map(cstring, ('d:\\goldmine',
'd:\\goldmine\\gmbase','d:\\goldmine\\demo','KARL','KAPPASIG'))
args=(s,g,c,u,p)
return self.calldll.call_foreign_function(
self.h_load,
'l'*len(args),
'l',
args
)
def unload(self):
return self.calldll.call_foreign_function(
self.h_unload,
'',
'l',
()
)
def die(self):
self.calldll.free_library(self.handle)


>>> from threading import *
>>> def test():
gm=GMdll()
lLock.acquire()
l.append(gm)
lLock.release()


>>> l=[]
>>> lLock=Lock()
>>> a=Thread(target=test)
>>> b=Thread(target=test)
>>> def tt():
a.start()
b.start()


>>> tt()
>>> l
[<__console__.GMdll instance at 839600>, <__console__.GMdll instance at
842910>]
>>> l[0].handle
22020096
>>> l[1].handle
22020096
>>>
New to threading. Right idea??? [ In reply to ]
On Sun, 13 Jun 1999, Karl Putland wrote:

> I need some advise. Am I on the right track?

Not quite. As you say, threads are independent paths of execution. The
key word there is "path of execution" =). In other words, everything but
the path of execution is shared, especially globals, and in Python, the
state of the interpreter. The two threads share the same list of imported
modules, etc.

What you're thinking of is processes, not threads. On unix, that's done
with a fork(). There is no simple equivalent on Windows, alas. Not that
it would help (see below).

> One of the functions in the dll is EXPENSIVE. It's not mine and I doubt
> they will rework it so I have to live with it. the EXPENSIVE function must
> be called at the begining and ties all activity in the dll to a specific
> directory. If you want to change directories you must call unexpensive then
> EXPENSIVE again with the new directory as an argument. If the dll is loaded
> and EXPENSIVE has been called sucessive calls to EXPENSIVE return FALSE.

If you must call EXPENSIVE for each directory, then you must -- I don't
think there's any way around that. Loading the same DLL multiple times
won't help if you have to call EXPENSIVE for each (especially if
unexpensive is, well, unexpensive =). If EXPENSIVE is VERY_EXPENSIVE,
where VERY_EXPENSIVE >> cost of loading the DLL, then even a fork()
wouldn't help much, even if it were available on your OS.

--david ascher
New to threading. Right idea??? [ In reply to ]
Thanks David.
>
> If you must call EXPENSIVE for each directory, then you must -- I don't
> think there's any way around that. Loading the same DLL multiple times
> won't help if you have to call EXPENSIVE for each (especially if
> unexpensive is, well, unexpensive =). If EXPENSIVE is VERY_EXPENSIVE,
> where VERY_EXPENSIVE >> cost of loading the DLL, then even a fork()
> wouldn't help much, even if it were available on your OS.
>
> --david ascher

I experimented with creating a copy of the dll with a diferent name and
loading it. This worked. I could call EXPENSIVE for the dll and the
copy_of_dll and both succeed.

The other interesting part of this is that EXPENSIVE executes over twenty
times faster the second time around. That is if dll and copy_of_dll are
both loaded, calling dll.EXPENSIVE takes between 1.5 and 4.8 seconds, then
calling copy_of_dll.EXPENSIVE takes .022 - .22. EXPENSIVE is really called
load_bde().

I guess that I will just manage the files to load one ofr more copies of the
dll since that seems to work like I need it to.

>>> from gm4s32 import *
>>> load_bde()
(1, 'Startup Time: 0.99999997139')
>>> copy_load_bde()
(1, 'Startup Time: 0.0499999523163')
>>>


***snippet from module gm4s32.py***
import windll
import time
import os
import string
from types import *

gm=windll.module('GM4S32')
gma=windll.module('GM4S3a')

##if raw_input('(W)ork or (H)ome: ')=='W':
## SysDir='G:\\'
## GoldDir='G:\\'
## CommonDir='g:\\merged'
## User='MASTER'
## Password='ACCESS'
##else:

SysDir='d:\\goldmine'
GoldDir='d:\\goldmine\\gmbase'
CommonDir='d:\\goldmine\\demo'
User='KARL'
Password='KAPPASIG'

def load_bde(sysDir='',
goldDir='',
commonDir='',
user='',
password=''):

global SysDir, GoldDir, CommonDir, User, Password

if not sysDir: sysDir=SysDir
if not goldDir: goldDir=GoldDir
if not commonDir: commonDir=CommonDir
if not user: user=User
if not password: password=Password

SysDir=sysDir
GoldDir=goldDir
CommonDir=commonDir
User=user
Password=password

start=time.time()
(sysDir, goldDir, commonDir,
user, password)=map(windll.cstring,(sysDir, goldDir, commonDir,
user, password))
return (gm.GMW_LoadBDE(sysDir, goldDir, commonDir, user, password),
"Startup Time: " + str(time.time()-start))

def unload_bde():
return gm.GMW_UnloadBDE()

def copy_load_bde(sysDir='',
goldDir='',
commonDir='',
user='',
password=''):

global SysDir, GoldDir, CommonDir, User, Password

if not sysDir: sysDir=SysDir
if not goldDir: goldDir=GoldDir
if not commonDir: commonDir=CommonDir
if not user: user=User
if not password: password=Password

SysDir=sysDir
GoldDir=goldDir
CommonDir=commonDir
User=user
Password=password

start=time.time()
(sysDir, goldDir, commonDir,
user, password)=map(windll.cstring,(sysDir, goldDir, commonDir,
user, password))
return (gma.GMW_LoadBDE(sysDir, goldDir, commonDir, user, password),
"Startup Time: " + str(time.time()-start))

def copy_unload_bde():
return gma.GMW_UnloadBDE()