
Fix your damned data races - dbaupp
https://blog.mozilla.org/nnethercote/2015/02/24/fix-your-damned-data-races/
======
falcolas
I'm reminded of an image I saw a few weeks ago:

The sign says "You must be at least this tall to write threaded code", and
it's been placed 8 feet off the floor, next to a well respected senior
developer who must constantly write threaded code (and who, when standing, is
a good two feet shy of the sign).

Threading properly is hard, and yet it's becoming more and more integrated
into our lives, from our browser to our backend interpreters like Node...

Concurrency needs a Rust-like language to protect us at compile time against
data races. The restrictions it would impose on what we could do might be
abhorrent to our generation of coders, but the benefits would be far reaching.

~~~
_pmf_
Shared memory is hard. Using threading in conjunction with message passing is
comparatively nice and safe.

~~~
falcolas
Race conditions can and do occur with message passing as well. All that is
required is to depend on operations split between threads (processes,
machines) occurring in a particular order, and you will eventually run into a
race condition when you try and run the code concurrently.

The problem occurs in that both programmers and our tools are terrible at
guessing when such order dependencies will occur, except when working with
"embarrassingly parallel" tasks.

~~~
chubot
But this isn't a "data race", which is what the article is about. Reasoning
about data races is different than reasoning about what happens when events
happen out of order. I would say the former is harder in general.

The default should be message passing concurrency, as Go advocates -- which of
course can be done with simple threads and queues. Unfortunately in C++ that
leads to tricky memory management issues.

~~~
falcolas
You are correct - not all race conditions are data races, and message
passing/immutable shared data will help prevent traditional shared memory
problems.

That said, you can still have a data race with "immutable" data at the thread
level as well.

For example, we have a system which has A processing threads, whose results
are collated by the master and passed to a set of B processing threads. All of
these threads use message passing and an immutable view of the master's
environment which determines their behavior.

A command comes in which changes the master's environment, and the master
sends the A and B threads a "die" command and waits for the flow of data out
of the threads to stop. It then spins up new A threads and B threads to
process the data with the new environment.

The data race appears when some old A threads become blocked on some external
resource or are just unlucky in scheduling, passing data based off of outdated
assumptions to the new B processors will be attempting to process data from
the original A threads which have the wrong view of data.

The solution in this case is obvious - set up new queues, or more
authoritatively kill off old threads, or change a parameter in the messages
being passed, or pass the entire state from thread to thread, or... but the
solutions to the problems outlined in the OP are also obvious, once the race
condition is identified.

------
rthomas6
Does coding in a pure functional language like Haskell solve this problem?

~~~
yshalabi
Yes. Functional languages are amenable to composition. Because of their
"purity". This allows trivial extraction of parallelism/concurrency. No need
to reason about interleaving and shared data and such.

But, I don't know if "use FP if you want parallelism" is an acceptable
solution currently. My intuition is that latency sensitive application can't
use these languages because they don't expose the low-level primitives (read
pointers) that make the difference in such applications. But I haven't written
and profiled enough FP code to know if this is absolutely the case.

~~~
zaphar
No, Functional languages reduce the problems surface area but they don't
eliminate it. You can still get data races and deadlocks in Haskell. They
aren't the same as a memory race in say C where the contents of a variable
might change out from under you in truly bizarre ways but you still get
algorithmic races where the wrong answer comes our the other end because two
parallel operations happened in the wrong order.

~~~
marcosdumay
You can't get deadlocks and data races on pure code.

Once your code is in a monad, every one of those problems may be back
(including memory race).

~~~
elihu
The IO monad in particular. Monads by themselves don't introduce
races/deadlocks.

------
josinalvo
So, how could I fix the first example of the paper ?
([https://www.usenix.org/legacy/events/hotpar11/tech/final_fil...](https://www.usenix.org/legacy/events/hotpar11/tech/final_files/Boehm.pdf),
section 2.1)

~~~
codygman
I'm not much of a C programmer and don't know the answer, but a total guess
based on intuition results in:

[http://www.gnu.org/software/libc/manual/html_node/Atomic-
Dat...](http://www.gnu.org/software/libc/manual/html_node/Atomic-Data-
Access.html#Atomic-Data-Access)

