1

it's my code:

import threading
x=0
class a(threading.thread)
    def run(self):
        global x
        for i in range(1000000):
             x+=1

class b(threading.thread)
    def run(self):
        global x
        for i in range(1000000):
             x-=1
def run():
    a().start()
    b().start()
    //after both thread done
    print x
run()

i expect this show me 0 (x=0) but every time i run it the result is pretty different(less than zero)
what's wrong with it?

Mehrdad Dadvand
  • 340
  • 4
  • 19
  • I tried to run your code; and I immediately hit a syntax error on 3rd line. Maybe you try posting code that actually runs? – GhostCat Aug 25 '16 at 11:15
  • its should be threading.Thread instead of thread.thread – famagusta Aug 25 '16 at 11:17
  • See [this](http://stackoverflow.com/questions/1717393/is-the-operator-thread-safe-in-python) post – FujiApple Aug 25 '16 at 11:17
  • Also, `//after both thread done` is not a legal Python comment, and since you didn't store a reference to the instances of `a` and `b`, I'm suspicious when you claim they're really done; if you don't call `join` on the threads, you don't know they're done. – ShadowRanger Aug 25 '16 at 11:18

1 Answers1

5

Race conditions. The actual operation of x += 1 is roughly:

  1. Load the value of x
  2. Compute x + 1
  3. Store the computed value to x

Except with threading, you might get preempted by the other thread after step 1 and before step 3 (whether it's before or after 2 doesn't matter). If the other thread sees the unincremented value, decrements that, then you store your incremented value before it stores the decremented value, you just dropped an increment; if they store before you do, you dropped a decrement.

You need to lock access to shared variables to ensure that the operation behaves atomically:

import threading
x=0
xlock = threading.Lock()
class a(threading.Thread):
    def run(self):
        global x
        for i in range(1000000):
             with xlock:
                 x+=1

class b(threading.Thread):
    def run(self):
        global x
        for i in range(1000000):
             with xlock:
                 x-=1

This may introduce quite a bit of overhead, so other alternatives that touch the shared variable less may be better options (at the expense of having different behaviors).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271