5

Is operation like a,b=1,2 atomic ?

Some background of my issue :I am working with signal . which are being raised from some external process. Here i want to avoid the cases when signal is being captured between setting a=1 and b=2. Is there any way to achieve this ?

Is there any way to check if given step is atomic or not ?

gsagrawal
  • 2,900
  • 4
  • 27
  • 27
  • See also: http://stackoverflow.com/questions/2623086/is-a-variable-swap-guaranteed-to-be-atomic-in-python – nemo Aug 01 '13 at 09:44

2 Answers2

12

It is not atomic because it takes multiple bytecode instructions to assign to multiple names and it doesn't take long to confirm it experimentally:

import signal

a = 1
b = 2

def handler(sig, trace):
    print a, b

def main():
    global a, b
    signal.signal(signal.SIGINT, handler)
    while True:
        a, b = 3, 4
        a, b = 1, 2

if __name__ == '__main__':
    main()

$ python atom.py
^C3 4
^C3 4
^C1 2
^C1 2
^C3 4
^C1 2
^C1 2
^C1 2
^C1 2
^C1 4 <<<< inconsistent state

In this particular case, if you want two values to change atomically, you can get away with assignment to tuple and accessing its elements in the signal handler. Looking at disassembly:

>>> a = 1
>>> b = 2
>>> c = (1, 2)
>>> def foo():
...     global a, b
...     a, b = 1, 2
... 
>>> def bar():
...     global c
...     c = (1, 2)
... 
>>> dis.dis(foo)
  3           0 LOAD_CONST               3 ((1, 2))
              3 UNPACK_SEQUENCE          2
              6 STORE_GLOBAL             0 (a)
              9 STORE_GLOBAL             1 (b)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE        
>>> dis.dis(bar)
  3           0 LOAD_CONST               3 ((1, 2))
              3 STORE_GLOBAL             0 (c)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

No matter how complex the value is, assignment to a variable (or dict entry, or object field) is a single atomic store operation.

rkhayrov
  • 10,040
  • 2
  • 35
  • 40
  • this is exactly what i wanted to check .. – gsagrawal Aug 01 '13 at 09:53
  • I think this answer is great. For future reference and visitors, someone (you? :-)) should take the time and add a detailed explanation of what is happening behind the scenes that leads to this inconsistent state (also incorporating information from the other answer, that `STORE_FAST (a)` is executed before `STORE_FAST (b)`). – Dr. Jan-Philip Gehrcke Aug 01 '13 at 09:54
4

No, the sequence assignment is not atomic. Just take a look at the byte code:

>>> def unpack():
        a,b=1,2

>>> import dis
>>> dis.dis(unpack)
  2           0 LOAD_CONST               3 ((1, 2))
              3 UNPACK_SEQUENCE          2
              6 STORE_FAST               0 (a)
              9 STORE_FAST               1 (b)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE        

The assignment takes multiple opcodes to evaluate the tuple and store the result in variables.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • so is it like this step contains 6 atomic operations ?? or this is of 2 atomic operation – gsagrawal Aug 01 '13 at 09:45
  • 1
    A single opcode instruction is atomic. A different thread can change the value in consideration anytime between any 2 opcodes. – Rohit Jain Aug 01 '13 at 09:51