Skip to content
Search

Python:threading

lastmod 2025-06-12created 2016-08-3115 edits

Value

Return a ctypes object allocated from shared memory. By default the return value is actually a synchronized wrapper for the object.

typecode_or_type determines the type of the returned object: it is either a ctypes type or a one character typecode of the kind used by the array module. *args is passed on to the constructor for the type.

If lock is True (the default) then a new recursive lock object is created to synchronize access to the value. If lock is a Lock or RLock object then that will be used to synchronize access to the value. If lock is False then access to the returned object will not be automatically protected by a lock, so it will not necessarily be “process-safe”.

Operations like += which involve a read and write are not atomic. So if, for instance, you want to atomically increment a shared value it is insufficient to just do

counter.value += 1

Assuming the associated lock is recursive (which it is by default) you can instead do

with counter.get_lock():
    counter.value += 1

Note that lock is a keyword-only argument.

Example

import multiprocessing
def worker1(v):
    with v.get_lock():
        v.value += 1

def worker2(v):
    with v.get_lock():
        v.value += 2

ctypes_int = multiprocessing.Value("i", 0)
print ctypes_int.value

# Output: 0

process1 = multiprocessing.Process(
    target=worker1, args=[ctypes_int])
process2 = multiprocessing.Process(
    target=worker2, args=[ctypes_int])

process1.start()
process2.start()
process1.join()
process2.join()

print ctypes_int.value

RLock

"Reentrant Lock"

Sometimes, when a function that acquires a lock calls itself recursively, the thread gets blocked and can no longer release the lock

With RLock(), if a thread that already holds the lock acquires it again, the lock count is incremented by 1 and it returns immediately.

"Solves the lock reacquisition problem"

Condition

import threading
import time

CONSUMER_COUNT = 10
PRODUCER_COUNT = CONSUMER_COUNT // 2

queue = []
cv = threading.Condition()

item_id = 0

class Consumer(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id

    def run(self):
        for i in range(5):
            cv.acquire()
            while len(queue) < 1:
                print('consumer({}) waiting...'.format(self.id))
                cv.wait()
            print('consumer({}) -> item({})'.format(self.id, queue.pop(0)))
            cv.release()
            time.sleep(0.5)


class Producer(threading.Thread):
    def run(self):
        global item_id
        for i in range(10):
            cv.acquire()
            item_id += 1
            queue.append(item_id)
            cv.notify()
            cv.release()
            time.sleep(0.7)


threads = []

for i in range(CONSUMER_COUNT):
    threads.append(Consumer(i))

for i in range(PRODUCER_COUNT):
    threads.append(Producer())

for th in threads:
    th.start()

for th in threads:
    th.join()

print('<End>')

Simple Condition and Lock example

from threading import Thread, Condition, Lock


class Demo(Thread):
    def __init__(self):
        self._done = False
        self._lock = Lock()
        self._condition = Condition(self._lock)

    def quit(self) -> None:
        with self._condition:
            self._done = True
            self._condition.notify_all()

    def is_done(self) -> bool:
        with self._condition:
            result = self._done
            self._condition.notify_all()
            return result

    def run(self) -> None:
        with self._condition:
            while not self._done:
                self._condition.wait()
                # TODO: run something ...

Interrupt the Main Thread

import _thread

_thread.interrupt_main()

Daemon Thread

To create a daemon thread:

thread = Thread(... daemon=True)

When the main program exits, daemon threads are forcibly terminated as well. Unlike regular threads, the main program does not wait for daemon threads to finish.

Specific differences

  • Regular thread (daemon=False) <- default
    • The main program waits until all regular threads finish
    • The program does not exit while the thread is running
  • Daemon thread (daemon=True)
    • Forcibly terminated immediately when the main program exits
    • Terminates along with the program even if its work is not finished

Use cases

Daemon threads are useful in situations such as:

  • Background monitoring
  • Log processing
  • Periodic cleanup tasks
  • Auxiliary tasks that don't affect the main work

See also

Favorite site

author Zer0 sitemap