Explanation of program's behavior (Python)
Question: 
    import threading
    
    shared_balance = 0
    
    class Deposit(threading.Thread):
        def run(self):
            for i in xrange(1000000):
                global shared_balance
                balance = shared_balance
                balance += 100
                shared_balance = balance
    
    class Withdraw(threading.Thread):
        def run(self):
            for i in xrange(1000000):
                global shared_balance
                balance = shared_balance
                balance -= 100
                shared_balance = balance
    
    thread1 = Deposit()
    thread2 = Withdraw()
    
    thread1.start()
    thread2.start()
    
    thread1.join()
    thread2.join()
    
    
    print shared_balance
    

Everytime I run this program it outputs a random number. If it deposits 100, 1
million times and withdraws 100, 1 million times then why isn't the output 0?


Answer: You need to use
[threading.Lock](http://docs.python.org/2/library/threading.html#lock-objects)
to access you variables safely :

    
    
    from threading import Thread, Lock
    
    shared_balance = 0
    
    class Deposit(Thread):
        def __init__(self, lock):
            super(Deposit, self).__init__()
            self.lock = lock
        def run(self):
            global shared_balance
            for i in xrange(1000000):
                with self.lock:
                    shared_balance += 100
    
    class Withdraw(Thread):
        def __init__(self, lock):
            super(Withdraw, self).__init__()
            self.lock = lock
        def run(self):
            global shared_balance
            for i in xrange(1000000):
                with self.lock:
                    shared_balance -= 100
    
    shared_lock = Lock()
    thread1 = Deposit(shared_lock)
    thread2 = Withdraw(shared_lock)
    
    thread1.start()
    thread2.start()
    
    thread1.join()
    thread2.join()
    
    print shared_balance
    

Output :

    
    
    >>> 0
    

Also, take a look at the bytecode generated for :

    
    
    a = 0
    def f():
        global a
        a += 10
    

Bytecode of "a += 10" :

    
    
     6 LOAD_GLOBAL              0 (a)     # Load global "a"  UNSAFE ZONE
     9 LOAD_CONST               2 (10)    # Load value "10"  UNSAFE ZONE
    12 INPLACE_ADD                        # Perform "+="     UNSAFE ZONE
    13 STORE_GLOBAL             0 (a)     # Store global "a" 
    16 LOAD_CONST               0 (None)  # Load "None"
    19 RETURN_VALUE                       # Return "None"  
    

In Python, a bytecode execution cannot be preempted. It makes it really
convenient to use for threading. But in that case, it takes 4 bytecode
executions to perform the '+=' operation. It means that any other bytecode of
any other thread is suceptible to be executed between these bytecodes. This is
what makes it unsafe and the reason why you should use locks.

