[ZODB-Dev] RE:[Zope-dev] Thread safety in Zope 2 (was: [Zope-dev]
zope 2 and non-multithread safe extensions) extensions)
Norfleet, Sheppard S.
sheppard.norfleet at ngc.com
Wed Aug 6 12:23:23 EDT 2003
Jim,
I know this is an old thread, but I have related question...
I am making a application level replication product for my company, and the
product spawns a daemon thread to look for incoming transactions. I have
gotten rid of all my database conflict errors and tested concurrency locks
pretty rigorously. The daemon thread opens its own database connection and
creates a new context for the product, and any change to the product is
fully bracketed by a python RLock.
I say its thread safe, but actually after a period of time it stops being
so. Since the original presentation thread has joined, I am wondering that
when another presention thread is created that references the product, that
Zope is creating a whole new RLock. If this is the case, how would I go
about creating a singleton RLock object?
P.S. Zope really should have a services thread that it offers up to
products. I saw ThreadedASync but it looks like its not the answer. Sigh.
Maybe I should write a proposal for one...
Regards,
Shep
********************************************************************
Anthony Baxter wrote:
>
> How should a Product that's not thread-safe indicate this to Zope 2?
It doesn't. It must be thread safe.
> Say, for the sake of argument, that I had an (unreleased) SNMP product
> that wasn't thread-safe. How will this play in Zope2?
It will work incorrectly unless the number of application treads
is limited to one (e.g. 'python z2.py -t1').
This topic deserves some more discussion. Which is the topic of this
note. :)
1. How can you tell if a product is thread safe?
If a Zope product defines *persistent* objects and
those objects don't use any *mutable* gloal or shared variables
(such as class attributes or default arguments), then the product
is thread safe! *Pay close attention to this. It could let
you off the hook!* :)
A key feature of Zope 2 (ZODB 3) is that (a copy of) a
persistent object is never accessed by more than one thread
(unless the programmer goes way out of thier way). Each thread
uses it's own database connection(s). Each connection has it's
own copies of persistent objects. This feature provides a major
simplification for application developers.
If a product *does* make use of mutable shared data, then the product
must take steps to assure that they are used safely. Some key examples
of shared data include:
- Variables defined in modules (globals),
- Variables defined in classes,
- Default arguments to Python functions.
Note that a mutable global variable can be thread safe without
special care in some cases. For example, thanks to the methods
append and pop, lists can be used as thread-safe stacks and
queues without any extra locks, because they are protected by the global
interpreter lock.
2. What can I do if my product is not thread safe?
I can think of two choices:
a. Make it thread safe,
b. Tell my "customers" that it can only be used in
Zope applications with a single application thread.
3. How do I achiev thread safety for my objects?
If they are persistent objects, you don't need to.
If they are non-persistent objects that are *only*
referenced by persistent objects, you also don't need to worry.
This is a big topic, but in many cases, simple approaches
can be used.
First, you can assure that only one thread can call operations
on your objects at one time and that data are accessed only through
operations. If your objects are of extension types, then the Python
global interpreter lock protects operations on them (unless they release
the
lock). If your objects are written in Python, you can protect them by
mixing in the 'Synchronized' class from the 'Sync' module.
The Synchronized class provides a per-instance lock that gets
automatically acquired and released on entry to and exit from
methods on your objects.
Second, you should, if possible, provide a thread-safe API for your
objects.
In a thread-safe API, the operations are self-contained. The meaning of
an operation depends on the history of operation calls. An example
of a non-thread-safe API is the regex API. Regex objects have a
'group' method whose results depend on results of previous 'search' and
'match' calls.
If you can't change the API for an object to make it thread safe, then
you
can often create a wrapper for the object that is thread safe (see for
example,
lib/python/ts_regex.py) or make sure that you only make thread safe
calls.
In many places in Zope, we make sure we only make thread safe calls on
regex objects
by storing references to the thread-safe methods rather than to compiled
regular expressions themselves.
If the approach sketched above doesn't work for you, then you need to
put on your thinking cap and get up to speed on thread programming.
Jim
************************************************************************
More information about the ZODB-Dev
mailing list