Python thread synchronization lock, semaphore

Keywords: Python less

Synchronization lock

import  time, threading

def addNum():
    global num
    num -= 1

num = 100

thread_list = []
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list:
    t.join()

print('final num:', num)

//Run result:
final num: 0
import  time, threading

def addNum():
    global num
    #num -= 1
    tmp = num
    time.sleep(0.00001)
    num = tmp - 1

num = 100

thread_list = []
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list:
    t.join()

print('final num:', num)

//Run result:
final num: 93 
//or
final num: 91
//or
final num: 94

Reason:
In the first program, num -= 1 is written so that the program executes too quickly (within the time of cup switching)
In the second program, num -= 1 was added to sleep time, and 100 threads switched before execution completed, resulting in the global num not returning properly.Quote the picture of the Great God and find that it summarizes very well:

In the example above, using the join method will stop the entire thread, causing the serialization, losing the meaning of multithreading, and we only need to execute the serialization when it comes to computing public data.

Computing common data using synchronous lock processing

import  time, threading

def addNum():
    global num

    lock.acquire()
    tmp = num
    time.sleep(0.00001)
    num = tmp - 1
    lock.release()


num = 100
lock = threading.Lock()
thread_list = []
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list:
    t.join()

print('final num:', num)

//Operation result:
final num: 0

Thread Deadlocks and Recursive Locks

import  threading, time

class myThread(threading.Thread):
    def doA(self):
        lockA.acquire()
        print(self.name, "gotlockA", time.ctime())
        time.sleep(3)
        lockB.acquire()
        print(self.name, "gotlockB", time.ctime())
        lockB.release()
        lockA.release()

    def doB(self):
        lockB.acquire()
        print(self.name, "gotlockB", time.ctime())
        time.sleep(2)
        lockA.acquire()
        print(self.name, "gotlockA", time.ctime())
        lockA.release()
        lockB.release()

    def run(self):
        self.doA()
        self.doB()

if __name__ == '__main__':
    lockA = threading.Lock()
    lockB = threading.Lock()
    threads = []
    for i in range(5):
        threads.append(myThread())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

#Run result:
Thread-1 gotlockA Sat Jul 28 15:09:31 2018
Thread-1 gotlockB Sat Jul 28 15:09:34 2018
Thread-1 gotlockB Sat Jul 28 15:09:34 2018
Thread-2 gotlockA Sat Jul 28 15:09:34 2018

Use recursive locks

import  threading, time

class myThread(threading.Thread):
    def doA(self):
        lock.acquire()
        print(self.name, "gotlockA", time.ctime())
        time.sleep(3)
        lock.acquire()
        print(self.name, "gotlockB", time.ctime())
        lock.release()
        lock.release()

    def doB(self):
        lock.acquire()
        print(self.name, "gotlockB", time.ctime())
        time.sleep(2)
        lock.acquire()
        print(self.name, "gotlockA", time.ctime())
        lock.release()
        lock.release()

    def run(self):
        self.doA()
        self.doB()

if __name__ == '__main__':
    lock = threading.RLock()
    threads = []
    for i in range(5):
        threads.append(myThread())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

//Run result:
Thread-1 gotlockA Sat Jul 28 15:19:35 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockA Sat Jul 28 15:20:00 2018

Semaphore

Semaphore or BoundedSemaphore manages a built-in counter used to control the concurrency of threads. Whenever acquire() is called, -1 is called, release() is called, +1 is called, and the counter cannot be less than 0. When the counter is 0, acquire() blocks the thread to a synchronous lock until release() is called by another thread.(similar to the concept of parking spaces).
The only difference between BoundedSemaphore and Semaphore is that the former checks if the value of the counter exceeds the initial value of the counter when release() is called and throws an exception if it exceeds.

import threading, time

class myThread(threading.Thread):
    def run(self):
        if semaphore.acquire():
            print(self.name)
            time.sleep(5)
            semaphore.release()

if __name__ == "__main__":
    semaphore = threading.Semaphore(5)
    thrs = []
    for i in range(20):
        thrs.append(myThread())
    for t in thrs:
        t.start()

#Run result:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-9
Thread-10
Thread-8
Thread-11
Thread-13
Thread-14
Thread-12
Thread-15
Thread-18
Thread-16
Thread-17
Thread-19
Thread-20
import threading, time

class myThread(threading.Thread):
    def run(self):
        if semaphore.acquire():
            print(self.name)
            time.sleep(5)
            semaphore.release()

if __name__ == "__main__":
    semaphore = threading.BoundedSemaphore(5)
    thrs = []
    for i in range(20):
        thrs.append(myThread())
    for t in thrs:
        t.start()

#Run result:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-8
Thread-10
Thread-9
Thread-7
Thread-12
Thread-14
Thread-15
Thread-13
Thread-11
Thread-16
Thread-17
Thread-20
Thread-19
Thread-18

Posted by slevytam on Tue, 28 Jan 2020 08:18:59 -0800