Sysread changes behavior in the presence of threads?

As a very rough rule of thumb, when I design a thread-hot system, I
generally try to make the contention ratio of every mutex no worse
than 1:100. I try for 1:1000 if I can get it. Regardless of the weight
of the mutex mechanism (Ruby’s can hardly be worse than the one in
multi-processor Windows builds), the cost of a missed
mutex-acquisition ends up being about that high. People often complain
to me that keeping lock-sets as small as possible works against the
goal of making threads easier to use. Well, it doesn’t because threads
are hard to use, period. I’ve found that with careful analysis, it’s
generally possible to keep a lock set minimal, ideally no larger
than one read and one write. Any more than that (incuding function
calls), and you’re often synchronizing more than you really need to.

Java programmers (who suffer simultaneously from horrible
thread-management in their language, and a culture of serious
thread-overuse) love to tell you about their new “wait-free”
programming model. Not a new idea, it just encourages you to make your
lock-sets so minimal that they will fit within a machine operation
that is guaranteed to run in one bus cycle. (Intel chips have
half-a-dozen such operations.) Just proves my point all the more.

2006/5/22, Francis C. [email protected]:

We’re threadjacking, so I’ll keep it short. The point of taking a very
restrictive view of synchronization is to prevent incorrect concurrency.
Your example depends on the implementation of aMap and of calculateValue not
to do evil things. (One of the evil things they can do is simply to run for
several milliseconds, or make a blocking I/O call. This can give you a bad
case of mutex contention, which is exceptionally costly in many modern
implementations.) This means that the program may change behavior with
respect to concurrency across platforms, hardware, and also across time (as
the code inside those called functions changes).

No, it will change with regard to timing but not with regard to
behavior (semantics).

The nightmare scenario is this: the client calls to say that your
mission-critical application stops running occasionally. It will be fine for
a month, and then it will stop twice in one week. You ask what did they do
differently, and the answer is always “nothing.” You ask what your
programmers changed, and the answer is always “nothing.” The problem is of
course completely non-reproducible. This is not a nice place to be, since
you can’t just blame the client’s environment.

I agree that getting MT programs right is harder than single threaded
applications - but that’s not a reason to basically disallow MT if it
fits the business problem well.

I suppose your answer to all this is: just code more carefully, and only use
well-debugged libraries. That of course is a partially-correct answer, but
achievable in practice only at some specific cost. My larger point is that
in the case of threads, this balance-point is often very hard to achieve at
reasonable cost.

No, my answer is that your rule prevents proper implementation of
business requirements. The point of the short example I presented was
that you have to make a sequence of operations mutually exclusive in
order to implemente the business requirement (have a thread safe cache
that is filled as values are requested…). You have to allow this in
order to implement correct thread safe programs. If you allow for
variable assignment only then it’s overly complex to implement the
semantics I demonstrated. (btw, assignment can be a complex
operation, too - just thing of C++ operator overloading)

I’ll let you have the last word, both because we’re offtopic, and because
threading is a religious issue to many people and so the question tends to
generate more heat than light :-). In my defense, I’ll only say that my
dislike of threads is rooted in many years of experience, and not a mere
prejudice.

I’m not religious here I just state the fact that your rule cripples
MT implementations.

Kind regards

robert