Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #47243 > unrolled thread

Thread-safe way to prevent decorator from being nested

Started byMichael <mw@d3i.com>
First post2013-06-06 09:48 -0700
Last post2013-06-07 11:07 +0200
Articles 2 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Thread-safe way to prevent decorator from being nested Michael <mw@d3i.com> - 2013-06-06 09:48 -0700
    Re: Thread-safe way to prevent decorator from being nested Peter Otten <__peter__@web.de> - 2013-06-07 11:07 +0200

#47243 — Thread-safe way to prevent decorator from being nested

FromMichael <mw@d3i.com>
Date2013-06-06 09:48 -0700
SubjectThread-safe way to prevent decorator from being nested
Message-ID<21b0b719-cdf9-4475-81ac-a429a1e65907@googlegroups.com>
I'm writing a decorator that I never want to be nested. Following from the answer on my StackOverflow question (http://stackoverflow.com/a/16905779/106244), I've adapted it to the following.

Can anyone spot any issues with this? It'll be run in a multi-threaded environment serving Django requests and also be a part of Celery tasks.


    import threading
    from contextlib import contextmanager
    from functools import wraps

    thread_safe_globals = threading.local()

    @contextmanager
    def flag():
        thread_safe_globals._within_special_context = True
        try:
            yield
        finally:
            thread_safe_globals._within_special_context = False

    def within_special_wrapper():
        try:
            return thread_safe_globals._within_special_context
        except AttributeError:
            return False

    def my_special_wrapper(f):
        @wraps(f)
        def internal(*args, **kwargs):
            if not within_special_wrapper():
                with flag():
                    f(*args, **kwargs)
            else:
                raise Exception("No nested calls!")
        return internal

    @my_special_wrapper
    def foo():
        print(within_special_wrapper())
        bar()
        print('Success!')

    @my_special_wrapper
    def bar():
        pass

    foo()

[toc] | [next] | [standalone]


#47321

FromPeter Otten <__peter__@web.de>
Date2013-06-07 11:07 +0200
Message-ID<mailman.2847.1370596054.3114.python-list@python.org>
In reply to#47243
Michael wrote:

> I'm writing a decorator that I never want to be nested. Following from the
> answer on my StackOverflow question
> (http://stackoverflow.com/a/16905779/106244), I've adapted it to the
> following.
> 
> Can anyone spot any issues with this? It'll be run in a multi-threaded
> environment serving Django requests and also be a part of Celery tasks.

I'm not sure I understand what you are trying to do, but this

>             if not within_special_wrapper():
>                 with flag():

looks suspiciously like race condition.

>    thread_safe_globals = threading.local()

I'm not an expert in the area, but I think you need a lock, something like

class NestingError(Exception):
    pass

nest_lock = threading.Lock()

def my_special_wrapper(f):
    @wraps(f)
    def internal(*args, **kwargs):
        if nest_lock.acquire(False): # non-blocking
            try:
                f(*args, **kwargs)
            finally:
                nest_lock.release()
        else:
            raise NestingError
    return internal

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web