Open In App

Python acquire()

Last Updated : 26 Feb, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Lock.acquire() method in Python's threading module is a fundamental operation to synchronize threads and control access to shared resources. It ensures that only one thread can execute a critical section at a time, preventing race conditions.

Python
import threading

# Create a Lock object
lock = threading.Lock()
shared_counter = 0

def increment():
    global shared_counter
    # Acquire the lock before entering the critical section
    if lock.acquire():
        try:
            print(f"Lock acquired by {threading.current_thread().name}")
            shared_counter += 1  # Critical section
        finally:
            lock.release()  # Ensure the lock is released
            print(f"Lock released by {threading.current_thread().name}")

# Create and start multiple threads
threads = []
for i in range(5):
    t = threading.Thread(target=increment)
    t.start()
    threads.append(t)

# Wait for all threads to complete
for t in threads:
    t.join()

print(f"Final counter value: {shared_counter}")

Output:

Lock acquired by Thread-17 (increment)
Lock released by Thread-17 (increment)
Lock acquired by Thread-18 (increment)
Lock released by Thread-18 (increment)
Lock acquired by Thread-19 (increment)
Lock released by Thread-19 (increment)
Lock acquired by Thread-20 (increment)
Lock released by Thread-20 (increment)
Lock acquired by Thread-21 (increment)
Lock released by Thread-21 (increment)
Final counter value: 5

Explanation:

  • lock.acquire() allows only one thread to enter the critical section.
  • shared_counter += 1 is the critical section where shared data is modified.
  • lock.release() ensures the lock is released after work is done, even if an error occurs.

Before using acquire(), we need to import the Lock class from the threading module:

from threading import Lock

Lock.acquire() Syntax

lock.acquire(blocking=True, timeout=-1)

Parameters:

blocking (optional):

  • True (default): thread waits until the lock becomes available.
  • False: thread does not wait; it acquires the lock if it's free, otherwise it moves on.

timeout (optional): Maximum time (in seconds) to wait for the lock.

  • -1 (default): Waits indefinitely.

Returns:

  • True: Lock was successfully acquired.
  • False: Lock was not acquired (when blocking=False or timeout occurs).

Lock.aquire() examples

Example 1: Non-Blocking Acquire

lock.acquire() can be used to attempt acquiring a lock without waiting, allowing threads to proceed only if the lock is available.

Python
lock = threading.Lock() # create lock

def try_lock():
    if lock.acquire(blocking=False): # Attempt to acquire the lock without waiting
        try:
            print(f"Lock acquired by {threading.current_thread().name}")
        finally:
            lock.release()
            print(f"Lock released by {threading.current_thread().name}")
    else:
        print(f"Lock not acquired by {threading.current_thread().name}")

threads = [threading.Thread(target=try_lock) for _ in range(3)]

for t in threads:
    t.start()

for t in threads:
    t.join()

Output

Lock acquired by Thread-3 (try_lock)
Lock released by Thread-3 (try_lock)
Lock acquired by Thread-4 (try_lock)
Lock released by Thread-4 (try_lock)
Lock acquired by Thread-5 (try_lock)
Lock released by Thread-5 (try_lock)

Explanation:

  • lock.acquire(blocking=False) tries to get the lock without waiting.
  • If lock is free, thread enters critical section otherwise, skips it.
  • Some threads may fail to acquire the lock if others are already holding it.

Example 2: Acquire with Timeout

lock.acquire() can be used to attempt acquiring a lock for a specific time, allowing threads to wait for the lock but proceed if it is not acquired within the timeout.

Python
import threading

lock = threading.Lock()

def try_lock_with_timeout():
    if lock.acquire(timeout=2):  # Try to acquire the lock for 2 seconds
        try:
            print(f"Lock acquired by {threading.current_thread().name}")
        finally:
            lock.release()
            print(f"Lock released by {threading.current_thread().name}")
    else:
        print(f"Lock not acquired by {threading.current_thread().name}")

threads = [threading.Thread(target=try_lock_with_timeout) for _ in range(3)]

for t in threads:
    t.start()

for t in threads:
    t.join()

Output

Lock acquired by Thread-14 (try_lock_with_timeout)
Lock released by Thread-14 (try_lock_with_timeout)
Lock acquired by Thread-15 (try_lock_with_timeout)
Lock released by Thread-15 (try_lock_with_timeout)
Lock acquired by Thread-16 (try_lock_with_timeout)
Lock released by Thread-16 (try_lock_with_timeout)

Explanation:

  • lock.acquire(timeout=2) waits for up to 2 seconds to acquire the lock.
  • Acquires the lock if available within 2 seconds otherwise, moves on.
  • Threads either acquire the lock or timeout after 2 seconds.

Best Practices

  • Always release the lock after acquiring it (prefer try-finally block).
  • Use blocking=False or timeout when immediate access is preferred or long waits are undesirable.
  • Avoid deadlocks: Ensure that every acquire() is paired with a release().

Similar Reads