@@ -260,3 +260,104 @@ thread, iterate over a copy:
260260
261261 Consider external synchronization when sharing :class: `dict ` instances
262262across threads.
263+
264+
265+ .. _thread-safety-bytearray :
266+
267+ Thread safety for bytearray objects
268+ ===================================
269+
270+ The :func: `len ` function is lock-free and :term: `atomic <atomic operation> `.
271+
272+ Concatenation and comparisons use the buffer protocol, which prevents
273+ resizing but does not hold the per-object lock. These operations may
274+ observe intermediate states from concurrent modifications:
275+
276+ .. code-block ::
277+ :class: maybe
278+
279+ ba + other # may observe concurrent writes
280+ ba == other # may observe concurrent writes
281+ ba < other # may observe concurrent writes
282+
283+ All other operations from here on hold the per-object lock.
284+
285+ Reading a single element or slice is safe to call from multiple threads:
286+
287+ .. code-block ::
288+ :class: good
289+
290+ ba[i] # bytearray.__getitem__
291+ ba[i:j] # slice
292+
293+ The following operations are safe to call from multiple threads and will
294+ not corrupt the bytearray:
295+
296+ .. code-block ::
297+ :class: good
298+
299+ ba[i] = x # write single byte
300+ ba[i:j] = values # write slice
301+ ba.append(x) # append single byte
302+ ba.extend(other) # extend with iterable
303+ ba.insert(i, x) # insert single byte
304+ ba.pop() # remove and return last byte
305+ ba.pop(i) # remove and return byte at index
306+ ba.remove(x) # remove first occurrence
307+ ba.reverse() # reverse in place
308+ ba.clear() # remove all bytes
309+
310+ Slice assignment locks both objects when *values * is a :class: `bytearray `:
311+
312+ .. code-block ::
313+ :class: good
314+
315+ ba[i:j] = other_bytearray # both locked
316+
317+ The following operations return new objects and hold the per-object lock
318+ for the duration:
319+
320+ .. code-block ::
321+ :class: good
322+
323+ ba.copy() # returns a shallow copy
324+ ba * n # repeat into new bytearray
325+
326+ The membership test holds the lock for its duration:
327+
328+ .. code-block ::
329+ :class: good
330+
331+ x in ba # bytearray.__contains__
332+
333+ All other bytearray methods (such as :meth: `~bytearray.find `,
334+ :meth: `~bytearray.replace `, :meth: `~bytearray.split `,
335+ :meth: `~bytearray.decode `, etc.) hold the per-object lock for their
336+ duration.
337+
338+ Operations that involve multiple accesses, as well as iteration, are never
339+ atomic:
340+
341+ .. code-block ::
342+ :class: bad
343+
344+ # NOT atomic: check-then-act
345+ if x in ba:
346+ ba.remove(x)
347+
348+ # NOT thread-safe: iteration while modifying
349+ for byte in ba:
350+ process(byte) # another thread may modify ba
351+
352+ To safely iterate over a bytearray that may be modified by another
353+ thread, iterate over a copy:
354+
355+ .. code-block ::
356+ :class: good
357+
358+ # Make a copy to iterate safely
359+ for byte in ba.copy():
360+ process(byte)
361+
362+ Consider external synchronization when sharing :class: `bytearray ` instances
363+ across threads. See :ref: `freethreading-python-howto ` for more information.
0 commit comments