Examples to explain the use of thread locks in Python programming

WBOY
Release: 2016-08-04 08:55:41
Original
1368 people have browsed it

Lock

Python's built-in data structures such as lists and dictionaries are thread-safe, but simple data types such as integers and floating-point numbers are not thread-safe. To operate these simple data types, you need to use locks.

#!/usr/bin/env python3
# coding=utf-8

import threading

shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 100000
shared_resource_lock = threading.Lock()

####LOCK MANAGEMENT##
def increment_with_lock():
  global shared_resource_with_lock
  for i in range(COUNT):
    shared_resource_lock.acquire()
    shared_resource_with_lock += 1
    shared_resource_lock.release()
    
def decrement_with_lock():
  global shared_resource_with_lock
  for i in range(COUNT):
    shared_resource_lock.acquire()
    shared_resource_with_lock -= 1
    shared_resource_lock.release()
    ####NO LOCK MANAGEMENT ##
  
def increment_without_lock():
  global shared_resource_with_no_lock
  for i in range(COUNT):
    shared_resource_with_no_lock += 1
  
def decrement_without_lock():
  global shared_resource_with_no_lock
  for i in range(COUNT):
    shared_resource_with_no_lock -= 1
  
####the Main program
if __name__ == "__main__":
  t1 = threading.Thread(target = increment_with_lock)
  t2 = threading.Thread(target = decrement_with_lock)
  t3 = threading.Thread(target = increment_without_lock)
  t4 = threading.Thread(target = decrement_without_lock)
  t1.start()
  t2.start()
  t3.start()
  t4.start()
  t1.join()
  t2.join()
  t3.join()
  t4.join()
  print ("the value of shared variable with lock management is %s"\
  %shared_resource_with_lock)
  print ("the value of shared variable with race condition is %s"\
  %shared_resource_with_no_lock)

Copy after login

Execution result:

$ ./threading_lock.py 

Copy after login
the value of shared variable with lock management is 0
the value of shared variable with race condition is 0

Copy after login

Another example:

import random
import threading
import time
logging.basicConfig(level=logging.DEBUG,
          format='(%(threadName)-10s) %(message)s',
          )
          
class Counter(object):
  def __init__(self, start=0):
    self.lock = threading.Lock()
    self.value = start
  def increment(self):
    logging.debug(time.ctime(time.time()))
    logging.debug('Waiting for lock')
    self.lock.acquire()
    try:
      pause = random.randint(1,3)
      logging.debug(time.ctime(time.time()))
      logging.debug('Acquired lock')      
      self.value = self.value + 1
      logging.debug('lock {0} seconds'.format(pause))
      time.sleep(pause)
    finally:
      self.lock.release()
def worker(c):
  for i in range(2):
    pause = random.randint(1,3)
    logging.debug(time.ctime(time.time()))
    logging.debug('Sleeping %0.02f', pause)
    time.sleep(pause)
    c.increment()
  logging.debug('Done')
counter = Counter()
for i in range(2):
  t = threading.Thread(target=worker, args=(counter,))
  t.start()
logging.debug('Waiting for worker threads')
main_thread = threading.currentThread()
for t in threading.enumerate():
  if t is not main_thread:
    t.join()
logging.debug('Counter: %d', counter.value)
Copy after login

Execution result:

$ python threading_lock.py 
Copy after login

(Thread-1 ) Tue Sep 15 15:49:18 2015
(Thread-1 ) Sleeping 3.00
(Thread-2 ) Tue Sep 15 15:49:18 2015
(MainThread) Waiting for worker threads
(Thread-2 ) Sleeping 2.00
(Thread-2 ) Tue Sep 15 15:49:20 2015
(Thread-2 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:20 2015
(Thread-2 ) Acquired lock
(Thread-2 ) lock 2 seconds
(Thread-1 ) Tue Sep 15 15:49:21 2015
(Thread-1 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:22 2015
(Thread-1 ) Tue Sep 15 15:49:22 2015
(Thread-2 ) Sleeping 2.00
(Thread-1 ) Acquired lock
(Thread-1 ) lock 1 seconds
(Thread-1 ) Tue Sep 15 15:49:23 2015
(Thread-1 ) Sleeping 2.00
(Thread-2 ) Tue Sep 15 15:49:24 2015
(Thread-2 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:24 2015
(Thread-2 ) Acquired lock
(Thread-2 ) lock 1 seconds
(Thread-1 ) Tue Sep 15 15:49:25 2015
(Thread-1 ) Waiting for lock
(Thread-1 ) Tue Sep 15 15:49:25 2015
(Thread-1 ) Acquired lock
(Thread-1 ) lock 2 seconds
(Thread-2 ) Done
(Thread-1 ) Done
(MainThread) Counter: 4
Copy after login

Acquire() passes a False value to check whether the lock is acquired. For example:

import logging
import threading
import time
logging.basicConfig(level=logging.DEBUG,
          format='(%(threadName)-10s) %(message)s',
          )
          
def lock_holder(lock):
  logging.debug('Starting')
  while True:
    lock.acquire()
    try:
      logging.debug('Holding')
      time.sleep(0.5)
    finally:
      logging.debug('Not holding')
      lock.release()
    time.sleep(0.5)
  return
          
def worker(lock):
  logging.debug('Starting')
  num_tries = 0
  num_acquires = 0
  while num_acquires < 3:
    time.sleep(0.5)
    logging.debug('Trying to acquire')
    have_it = lock.acquire(0)
    try:
      num_tries += 1
      if have_it:
        logging.debug('Iteration %d: Acquired',
               num_tries)
        num_acquires += 1
      else:
        logging.debug('Iteration %d: Not acquired',
               num_tries)
    finally:
      if have_it:
        lock.release()
  logging.debug('Done after %d iterations', num_tries)
lock = threading.Lock()
holder = threading.Thread(target=lock_holder,
             args=(lock,),
             name='LockHolder')
holder.setDaemon(True)
holder.start()
worker = threading.Thread(target=worker,
             args=(lock,),
             name='Worker')
worker.start()
Copy after login

Execution result:

$ python threading_lock_noblock.py 
Copy after login

(LockHolder) Starting
(LockHolder) Holding
(Worker  ) Starting
(LockHolder) Not holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 1: Acquired
(LockHolder) Holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 2: Not acquired
(LockHolder) Not holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 3: Acquired
(LockHolder) Holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 4: Not acquired
(LockHolder) Not holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 5: Acquired
(Worker  ) Done after 5 iterations

Copy after login

Thread safe lock

threading.RLock()
Copy after login

Returns a reentrant lock object. A reentrant lock must be released by the thread that acquired it. Once a thread acquires a reentrant lock, the same thread can acquire it again without blocking, and must be released after acquisition.

Usually a thread can only acquire the lock once:

import threading

lock = threading.Lock()

print 'First try :', lock.acquire()
print 'Second try:', lock.acquire(0)

Copy after login

Execution result:

$ python threading_lock_reacquire.py
Copy after login

First try : True
Second try: False
Copy after login

Use RLock to obtain multiple locks:

import threading
lock = threading.RLock()
print 'First try :', lock.acquire()
print 'Second try:', lock.acquire(0)
Copy after login

Execution result:

python threading_rlock.py 
Copy after login

First try : True
Second try: 1
Copy after login

Let’s look at another example:

#!/usr/bin/env python3
# coding=utf-8
import threading
import time
class Box(object):
  lock = threading.RLock()
  def __init__(self):
    self.total_items = 0
  def execute(self,n):
    Box.lock.acquire()
    self.total_items += n
    Box.lock.release()
  def add(self):
    Box.lock.acquire()
    self.execute(1)
    Box.lock.release()
  def remove(self):
    Box.lock.acquire()
    self.execute(-1)
    Box.lock.release()
    
## These two functions run n in separate
## threads and call the Box's methods    
def adder(box,items):
  while items > 0:
    print ("adding 1 item in the box\n")
    box.add()
    time.sleep(5)
    items -= 1
    
def remover(box,items):
  while items > 0:
    print ("removing 1 item in the box")
    box.remove()
    time.sleep(5)
    items -= 1
    
## the main program build some
## threads and make sure it works
if __name__ == "__main__":
  items = 5
  print ("putting %s items in the box " % items)
  box = Box()
  t1 = threading.Thread(target=adder,args=(box,items))
  t2 = threading.Thread(target=remover,args=(box,items))
  t1.start()
  t2.start()
  t1.join()
  t2.join()
  print ("%s items still remain in the box " % box.total_items)
Copy after login

Execution result:

$ python3 threading_rlock2.py 
Copy after login

putting 5 items in the box 
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
0 items still remain in the box
Copy after login
Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template