On Wed, Apr 27, 2022 at 2:47 PM Elijah Stone <[email protected]> wrote: > 1. should the lock be recursive or no?
After sleeping on this... I've been working with this issue from a variety of perspectives for most of my programming career. I won't bore you with those details. But ... I would summarize three major perspectives for dealing with locking: Below the level of abstraction for the locks (e.g. hardware), locking does not exist as an abstraction. Everything happens in parallel and locking is out of the picture. (In hardware, at a low level you synchronize based on your inputs, and maybe use a clock to keep things in sync, if the design has gotten out of control / has become too complex to understand.) At the level of abstraction of the locks, you need a careful, disciplined approach or you don't understand what's going on. Locking here is about providing consistent access to resources, and you need to enumerate those and you need to be concerned about time. You get deadlocks when different parts of your code lock multiple elements from the same set of resources in a different order from in other parts of your code. Above the level of abstraction of the locks, they're something of a mystery -- things work, or they don't, and you develop habits based on that, and use superstition if necessary to cope with the consequences. (The internet is maybe a good example here.) In communicating systems, you deal with issues of atomicity by either designing your system to work with stale data (e.g. analytics) or by designing your system to be cheap and throwaway (e.g. editing systems, or erlang). When things go wrong in a feedback loop you start over (or give up (or give up and start over)). And, in the end, there's always going to be someone who doesn't like it, and there's a certain amount of back and forth as a consequence. Anyways... this choice -- between re-entrant and non-reentrant locking -- winds up being useful or not based on your system architecture. Given a mechanism to achieve atomicity, ... once you have one kind of lock you can build the other kind on top of it. And, at the end of the day, you're going to need both. So... after sleeping on this... my gut feeling is that non-reentrant locking is best thought of as a "relatively global" "extremely short term" low level mechanism which gets used when constructing longer term reentrant locks. And, when reading the literature on these kinds of topics, I think it's important to understand the author's perspective -- the level of abstraction they were working at, the kinds of things that they were building, and the nature (and timing) of the feedback loops they were working with, and ideally some of the details of the problems they were tackling, But when talking about the J implementation and J's internal resources (J's "variables" or "names), it makes sense to me to use non-reentrant locks inside the implementation to provide reentrant locking which locks and unlocks J's internal resources at the same level of abstraction as J's stack (which is J's primary "reentrant code mechanism"). -- Raul ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
