do I need lock to protect python 2.7 list in multi-threaded environment?
<p>Wondering if we need lock on a Python list if multiple threads needs to access (read/write/get size)? Using Python 2.7 on Mac.</p>

<p>I have written a prototype to add a lock to protect the list. Not sure if necessary or any issues (for both performance and functional) in my code? Thanks.</p>

<p>BTW, I have the same question on Python dictionary and deque, about whether we need lock to protect it in a multi-threaded environment. Thanks.</p>

<pre><code>import threading
import time
import random

class checkStatus:
    def __init__(self):
        self.message = []
        self.lock = threading.Lock()
    def checkInStatus(self, msg):
        self.lock.acquire()
        self.message.append(msg)
        self.lock.release()
    def checkOutStatus(self):
        self.lock.acquire()
        if len(self.message) &gt; 0:
            msg = self.message.pop(0)
        else:
            msg = 'Queue empty'
        self.lock.release()
        return msg
    def checkMessageStatus(self):
        self.lock.acquire()
        size = len(self.message)
        self.lock.release()
        return size

messageQueue = checkStatus()

class myThread (threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
    def run(self):
        global messageQueue
        while True:
            time.sleep(1+5*random.random())
            print "%s: %s : %s" % (self.name, time.ctime(time.time()), messageQueue.checkMessageStatus())
            time.sleep(1 + 5 * random.random())
            msg = time.ctime(time.time()) + ' ' + self.name
            print "%s: %s : check in message, %s" % (self.name, time.ctime(time.time()), msg)
            messageQueue.checkInStatus(msg)
            time.sleep(1 + 5 * random.random())
            print "%s: %s : check out message, %s" % (self.name, time.ctime(time.time()), messageQueue.checkOutStatus())


if __name__ == "__main__":
    threads = []

    # Create new threads
    thread1 = myThread(1, "Thread-1")
    thread2 = myThread(2, "Thread-2")

    # Start new Threads
    thread1.start()
    thread2.start()

    # Add threads to thread list
    threads.append(thread1)
    threads.append(thread2)

    # Wait for all threads to complete
    for t in threads:
        t.join()
    print "Exiting Main Thread"
</code></pre>

<p>Output,</p>

<pre><code>Thread-2: Tue Aug 30 22:08:04 2016 : 0
Thread-1: Tue Aug 30 22:08:05 2016 : 0
Thread-1: Tue Aug 30 22:08:07 2016 : check in message, Tue Aug 30 22:08:07 2016 Thread-1
Thread-2: Tue Aug 30 22:08:07 2016 : check in message, Tue Aug 30 22:08:07 2016 Thread-2
Thread-2: Tue Aug 30 22:08:09 2016 : check out message, Tue Aug 30 22:08:07 2016 Thread-1
Thread-1: Tue Aug 30 22:08:11 2016 : check out message, Tue Aug 30 22:08:07 2016 Thread-2
Thread-2: Tue Aug 30 22:08:11 2016 : 0
Thread-1: Tue Aug 30 22:08:13 2016 : 0
Thread-2: Tue Aug 30 22:08:15 2016 : check in message, Tue Aug 30 22:08:15 2016 Thread-2
Thread-1: Tue Aug 30 22:08:17 2016 : check in message, Tue Aug 30 22:08:17 2016 Thread-1
Thread-2: Tue Aug 30 22:08:18 2016 : check out message, Tue Aug 30 22:08:15 2016 Thread-2
Thread-1: Tue Aug 30 22:08:19 2016 : check out message, Tue Aug 30 22:08:17 2016 Thread-1
</code></pre>

<p>Your <code>checkOutStatus</code> method requires a lock to work properly; the other methods do not since they are performing atomic operations (simple Python statement are atomic, see this <a href="http://effbot.org/zone/thread-synchronization.htm" rel="nofollow">reference</a>).  Without a lock in checkOutStatus, there can be a case where the if statement evaluates to True but a thread switch occurs immediately, before retrieving the message with <code>self.message.pop(0)</code>.  If the second thread then removes the message, when the first thread continues it will attempt to pop from an empty list.  If you rewrite the function as follows:</p>

<pre><code>def checkOutStatus(self):
    try:
        msg = self.message.pop(0)
    except IndexError:
        msg = 'Queue empty'
    return msg
</code></pre>

<p>it too will be threadsafe, since the only operation is atomic.  In that case you could drop all the locking code.</p>

python multithreading python-2.7