Do I need a lock here?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • jasiu85

    #1

    Do I need a lock here?

    Hey,

    Please take a look at the code of the two threads below:

    COMMON_DICT = {}

    def thread_1():
    global COMMON_DICT
    local_dict = prepare_dict()
    COMMON_DICT = local_dict

    def thread_2():
    global COMMON_DICT
    local_dict = COMMON_DICT
    use_dict(local_ dict)

    Do I need a lock to protect the COMMON_DICT dictionary? AFAIK bytecode
    operations are atomic and in each thread there's only one crucial
    bytecode op: STORE_NAME in the first thread and LOAD_NAME in the
    second one. So I suspect that everything will work just fine. Am I
    right?

    Regards,

    Mike
  • Duncan Booth

    #2
    Re: Do I need a lock here?

    jasiu85 <jasiu85@gmail. comwrote:
    Hey,
    >
    Please take a look at the code of the two threads below:
    >
    COMMON_DICT = {}
    >
    def thread_1():
    global COMMON_DICT
    local_dict = prepare_dict()
    COMMON_DICT = local_dict
    >
    def thread_2():
    global COMMON_DICT
    local_dict = COMMON_DICT
    use_dict(local_ dict)
    >
    Do I need a lock to protect the COMMON_DICT dictionary? AFAIK bytecode
    operations are atomic and in each thread there's only one crucial
    bytecode op: STORE_NAME in the first thread and LOAD_NAME in the
    second one. So I suspect that everything will work just fine. Am I
    right?
    >
    Possibly, but without further information it is impossible to tell.

    You have one thing wrong though: bytecode operations are not all atomic.
    For example STORE_NAME will remove a reference to the object previously
    stored under a name and that could trigger code in a __del__ method or a
    weak reference callback. That callback code will execute in the same thread
    as the STORE_NAME, but while it is executing you could get a context switch
    to another thread.

    None of that will prevent the store working, and it may not be at all
    applicable to your data structures, but in general any operation which can
    release complex objects is not thread safe.

    --
    Duncan Booth http://kupuguy.blogspot.com

    Comment

    • Michael Sparks

      #3
      Re: Do I need a lock here?

      jasiu85 wrote:
      Do I need a lock to protect the COMMON_DICT dictionary? AFAIK bytecode
      operations are atomic and in each thread there's only one crucial
      bytecode op: STORE_NAME in the first thread and LOAD_NAME in the
      second one. So I suspect that everything will work just fine. Am I
      right?
      Will it crash your system? Probably not. Will you end up with correct values
      in your dict? Probably not, since you can still end up with race hazards.

      If you want to share data that way, you may want to look at Kamaelia's
      STM[1] model, which is described on this page:

      * http://www.kamaelia.org/STM

      You can created stores - which are /essentially/ (key value) threadsafe
      stores which enable you to figure out when things go wrong, so you can do
      something about it ! :)

      A short example:

      from Axon.STM import Store

      S = Store() # Shared store (like your COMMON_DICT)

      D = S.using("accoun t_one", "account_tw o", "myaccount" )
      D["account_on e"].set(50)
      D["account_tw o"].set(100)
      D.commit() # This will fail if any of the values have changed
      S.dump()

      D = S.using("accoun t_one", "account_tw o", "myaccount" )
      D["myaccount"].set(D["account_on e"].value+D["account_tw o"].value)
      D["account_on e"].set(0)
      D["account_tw o"].set(0)
      D.commit() # This will fail if any of the values have changed
      S.dump()

      If this looks familiar, it's the same basic idiom as version control. The
      nice thing of course, is in this version you don't need to worry about
      locks, but just be aware that the .commit() may fail, and you may need to
      retry.

      Two examples - one using bare threads, one using Kamaelia components are
      here:
      * http://kamaelia.googlecode.com/svn/t.../Examples/STM/

      Crucially whilst the above says "this will fail", the examples in that
      directory handle the failures correctly :)

      This code is included in the latest Kamaelia release, described here:
      * http://www.kamaelia.org/GetKamaelia

      However you can also use the standalone tarball attached to that page.

      [1] ie a minimal software transactional memory implementation. The point of
      these things really is to allow you to detect when something has gone
      wrong (eg and update fails) and to redo the thing that led to the
      update. It's conceptually very similar to version control for variables.
      I'm tempted to replace "using" with "checkout" to mirror "commit".



      Michael.
      --


      Comment

      Working...