All Manuals > LispWorks® User Guide and Reference Manual > 19 Multiprocessing

19.14 Some mistakes to avoid with multithreading

This section describes some mistakes to avoid when using multithreading.

19.14.1 Closures

A closure is created when a function uses lexical variables from an outer function. The variables are said to be closed over by the closure.

If a closure is passed to another thread (for example in a mailbox or by funcall-async), then these variables should be treated in the same way that you would treat other globally accessible data. In general, that means using a lock to control access to them.

19.14.2 Use of with-slots

When you use the with-slots macro, code that appears to be accessing a variable is actually making a call to slot-value. You need to be aware that this might contain globally accessible data or might change unexpectedly.

For example, this code checks the value of a slot and then uses it:

(with-slots (things-vec) something
  (when things-vec
    (svref things-vec 0)))

If another thread can set the things-vec slot to nil, then the test above may fail, because things-vec actually refers to the slot in the object bound to something. If the setting happens between the test and the evaluation of the svref form, then svref will be called with nil and will signal an error.

The safe way to guard against this is to bind a local variable that cannot be changed by another thread:

(with-slots (things-vec) something
  (when-let (tv things-vec)
    (svref tv 0)))

This is also more efficient, because it removes a slot access.

LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:21