Question

I was trying to ask this question in StackOverflow, but later realized that this question is more relevant to general computer science, not specific engineering problems. If you think it's not, please let me know.

Recently I've found out what CSP(Communicating Sequential Processes) is.

According to the article Bell Labs and CSP Threads:

Most computer science undergraduates are forced to read Andrew Birrell's “An Introduction to Programming with Threads.” The SRC threads model is the one used by most thread packages currently available. The problem with all of these is that they are too low-level. Unlike the communication primitive provided by Hoare, the primitives in the SRC-style threading module must be combined with other techniques, usually shared memory, in order to be used effectively...

Another article Share memory by communicating from Golang blog says:

Traditional threading models (commonly used when writing Java, C++, and Python programs, for example) require the programmer to communicate between threads using shared memory (...)

Go's concurrency primitives - goroutines and channels - provide an elegant and distinct means of structuring concurrent software. (These concepts have an interesting history that begins with C. A. R. Hoare's Communicating Sequential Processes.)

Based on what I've seen so far, because Hoare proposed CSP in 1978, it seems that there was no reason to use SRC thread model in programming languages ​​like C++(1985), Java(1995) or Python(1990).

So my question is, why the most dominant programming languages didn't follow Hoare's thread model?

Here's my guesses:

  1. Most programmers back then didn't know about Hoare's thread model.
  2. Most programmers are used to traditional thread model.

What do you think?

Was it helpful?

Solution

Practically speaking, the C++ threading (memory) model is directly inspired by the Java Memory Model, and C followed. Hans Böhm was closely involved with the process and has a great resource list. (*)

You'll quickly note that your dates are pretty optimistic - this memory model did not exist in 1985 when the first C++ implementations were created. There's a practical reason for this. Even in 2000, it wasn't clear which model of parallel computing was going to win. Parallel extensions to mainstream languages were first defined as ad-hoc extensions by the hardware vendors, and later partially standardized by such things as POSIX threads and MPI.

Because of the challenges involved, you see that parallelism support is added first to languages used in high-performance computing. Even C++ was a bit late to the party; C and FORTRAN were the main languages. Java, by virtue of being late, had a chance to learn lessons from those. And since it was designed as a portable language, Java needed a clean memory model not tied to a particular hardware vendor's implementation.

So the common memory model can be traced to various actual hardware implementations that could be unified by a single definition. And this led to a secondary effect: because this was now a standard, software started to use it, and hardware vendors generally followed suit.

There's another winner in the parallelism space: GPGPU's. They entered the competition via a different way. NVidia's CUDA is a similar vendor-extension to C, C++ and FORTRAN. This was possible because the GPU market justified independent development, and the general-purpose use of GPU's was a lucky coincidence.

* This development can be dated pretty accurately, the use of the Java memory model for C++ was presented at the 2001-10 ISO C++ meeting in Redmond, WA.

OTHER TIPS

There are many approaches for concurrency, with different tradeoffs. We have threads with shared mutable state (e.g., SRC-style threading). We have coroutines (like Go). We have actor models with independent processes communicating via message passing (like Erlang or E).

I would put CSP on a different level. It's not the same sort of thing. The form of CSP that I am familiar with is a mathematical, theoretical formalism that can be used to model concurrent systems. It's not really a model of programming that can be directly used in programming languages. It's more like the lambda calculus. You can build programming language APIs inspired by CSP, just like Lisp and Scheme are inspired by the lambda calculus, but it's not directly a design of a thread API itself.

Why did early languages choose to follow the SRC model rather than something inspired by CSP? Well, all I can share with you is speculation. The SRC model is a low-level model that maps pretty closely to the primitives provided by processors: it is a thin level of abstraction over that. Just like C is a thin layer over assembly language (and doesn't use, say, functional or declarative paradigms), it's not surprising that early languages would provide a thin layer over processor primitives (rather than, say, other theoretical paradigms). Also, the SRC model works well with existing code and existing programming languages. You can take existing sequential code and then add threads. When you're writing threaded code, the sequential part of the computation looks just like code written for a non-threaded language. That backwards compatibility and familiarity was probably significant. The SRC model could be deployed as a library, without requiring changes to programming language syntax or compilers. I have to imagine that might have been a significant factor in its adoption. Also, the SRC model is somewhat similar in many ways to existing Unix primitives for running code in parallel in multiple processes, which I imagine might also have been beneficial for adoption. This is just my speculation. Perhaps someone else will be able to provide a more researched answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with cs.stackexchange
scroll top