PyVISA
PyVISADocs

Resource Locking

How to use PyVISA resource locking to safely share instruments across multiple scripts and processes.

When two scripts talk to the same instrument at the same time, commands interleave and results corrupt. PyVISA's locking mechanism prevents this with exclusive and shared locks.

Exclusive Lock

An exclusive lock gives one session full control. Other sessions block on any read/write until you release it.

import pyvisa

rm = pyvisa.ResourceManager()
dmm = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
dmm.timeout = 10000

try:
    dmm.lock_excl(timeout=5000)

    dmm.write("*RST")
    dmm.write("CONF:VOLT:DC 10, 0.001")
    voltage = float(dmm.query("READ?"))
    print(f"DC Voltage: {voltage:.6f} V")

    dmm.unlock()
finally:
    dmm.close()
    rm.close()

Log measurements automatically

TofuPilot records test results from your PyVISA scripts, tracks pass/fail rates across stations sharing the same instruments. Free to start.

Use lock_context to Avoid Forgetting unlock

If your code throws an exception between lock() and unlock(), the instrument stays locked until the session closes. Use lock_context() to handle this automatically.

import pyvisa

rm = pyvisa.ResourceManager()
dmm = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
dmm.timeout = 10000

try:
    with dmm.lock_context(timeout=5000):
        dmm.write("CONF:VOLT:DC")
        voltage = float(dmm.query("READ?"))
        print(f"Voltage: {voltage:.6f} V")

        dmm.write("CONF:RES")
        resistance = float(dmm.query("READ?"))
        print(f"Resistance: {resistance:.2f} ohm")
    # Lock released here, even if an exception was raised
finally:
    dmm.close()
    rm.close()

Always use lock_context

Calling lock_excl() and unlock() manually is error-prone. If anything raises between the two calls, the lock holds until session close. Prefer lock_context().

Shared Lock

A shared lock allows multiple sessions to read from an instrument simultaneously, but blocks exclusive lock requests. Useful for monitoring scripts that only query status.

import pyvisa

rm = pyvisa.ResourceManager()
dmm = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")

try:
    with dmm.lock_context(timeout=5000, requested_key="monitor_group"):
        # Multiple scripts using the same key can hold this lock
        idn = dmm.query("*IDN?")
        stb = dmm.read_stb()
        print(f"Instrument: {idn.strip()}")
        print(f"Status byte: {stb:#04x}")
finally:
    dmm.close()
    rm.close()

When you pass a requested_key, PyVISA requests a shared lock. All sessions using the same key can access the instrument concurrently. An exclusive lock request will block until all shared locks release.

Two Scripts Sharing a Network DMM

Script A runs a measurement sequence with an exclusive lock. Script B monitors the DMM status with a shared lock. They never step on each other.

Script A (measurement):

import pyvisa
import time

rm = pyvisa.ResourceManager()
dmm = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
dmm.timeout = 10000

try:
    with dmm.lock_context(timeout=10000):
        dmm.write("*RST")
        dmm.write("CONF:VOLT:DC 10, 0.0001")
        dmm.write("SAMP:COUN 50")
        dmm.write("TRIG:SOUR IMM")
        dmm.write("INIT")
        time.sleep(2)

        data = dmm.query("FETC?")
        values = [float(v) for v in data.strip().split(",")]
        print(f"Measured {len(values)} samples, mean: {sum(values)/len(values):.6f} V")
finally:
    dmm.close()
    rm.close()

Script B (monitor):

import pyvisa

rm = pyvisa.ResourceManager()
dmm = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")

try:
    with dmm.lock_context(timeout=5000, requested_key="status_monitor"):
        idn = dmm.query("*IDN?")
        err = dmm.query("SYST:ERR?")
        print(f"Instrument: {idn.strip()}")
        print(f"Error queue: {err.strip()}")
finally:
    dmm.close()
    rm.close()

Lock Types

Lock typeMethodBlocks others?Multiple holders?Use case
Exclusivelock_excl() or lock_context()Yes, all access blockedNo, single holderMeasurement sequences, configuration
Sharedlock_context(requested_key="...")Blocks exclusive onlyYes, same keyStatus monitoring, read-only queries

Timeout Behavior

ScenarioWhat happens
Lock availableAcquired immediately, returns
Lock held, timeout > 0Blocks up to timeout (ms), raises VisaIOError on expiry
Lock held, timeout = 0Fails immediately with VisaIOError
Lock held, timeout = VI_TMO_INFINITEBlocks indefinitely until lock is released

Common Pitfalls

ProblemFix
Lock not released on exceptionUse lock_context() instead of manual lock_excl()/unlock()
Script hangs waiting for lockSet a finite timeout, check if another script crashed while holding the lock
Shared lock blocks exclusiveAll shared lock holders must release before exclusive can acquire
Lock works locally but not over networkBoth scripts must connect to the same VISA resource string