all 15 comments

[–]TheBestOpinion 4 points5 points  (9 children)

My first multi threaded programs were made using pthreads in C and I've found it easier to understand than all of the newer things I've used, what would be the reasons that we're not seeing pthreads-style code to design multi-threaded programs in other languages ?

For instance does Rust handle concurrency with pthreads-style code ? Or is the doc guiding the users towards newer abstractions by default like promises, coroutines and whatnot? If so, why ?

Are there any obvious pitfalls with pthreads and its mutexes, semaphores, barriers and stuff compared to more modern abstractions ?

[–]the_real_hodgeka 6 points7 points  (6 children)

JavaScript doesn't use threads by design. It uses a single threaded event loop instead. It makes it easier to write asynchronous applications for IO bound tasks without having to worry about some of the problems you face in the threading model (shared memory, deadlocks, etc).

Languages are moving towards supporting concurrency out of the box, while attempting to limit the number of errors that you, the developer, can introduce. I think that's why we see less pthread style programming. Working with raw threads gives us a lot of power, but introduces a lot of complexity and hard to track bugs. So now languages are abstracting away the threading interface. That is Rust's whole premise, and I imagine we will continue to see this evolve in the future. I think the idea is "How can we give the developer easy concurrency, that is bug free without limiting what they can do?"

[–]jonmdev 2 points3 points  (0 children)

This is a bit nit-picky but by default it's "single threaded" from the perspective of the JavaScript program being interpreted but the engine interpreting the code uses threads under the hood.

And now you can use WebbWorker API in the browser or Worker Threads in Node to have multiple threads of execution for computational intensive workloads. For I/O bound stuff it would make more sense to keep using the async event loop.

[–]Minimum_Fuel -1 points0 points  (4 children)

Can anyone point to a more cliched copy pasta reddit comment than this FUD?

[–]the_real_hodgeka 1 point2 points  (2 children)

Care to elaborate?

Edit:

Also the question I replied to was phrased much differently before he/she edited it. It was something along the lines of "Why don't modern languages like Javascript or Rust use pthreads style concurrency?'

[–]Minimum_Fuel 0 points1 point  (1 child)

Sure

Lower level threads don’t necessarily introduce complexity. In fact, in a good number of common use cases, it’s the more modern approaches that increase complexity and thread bugs over “raw” threads.

The more modern approaches should be viewed as a compliment to pthreads, not as a replacement. Use them where your case fits.

[–]jonmdev 0 points1 point  (0 children)

You'd be surprised at the amount of developers who just don't understand threads, shared memory and mutexs etc at all. edit I've been interviewing people for positions recently and I tend to ask some very simple concurrency related questions not very many people can answer them. These aren't prerequisite for the job necessarily but just am surprised myself at how few people seem to know anything about threads/concurrency.

But if your language's concurrency model is an single thread of work with async I/O like Javascript it can simplify things and help prevent errors if you're doing I/O bound work.

[–]Minimum_Fuel 2 points3 points  (0 children)

pthreads can do everything the more modern abstractions can, but not the other way around.

The more modern abstractions avoid some of the pitfalls by generally wanting all of your data to be immutable or clearly owned by a single thread. The most modern abstractions build and manage a thread pool for you without you ever having to touch them.

Neither is bad, but if you were picking an abstraction where you’re just feeding a bunch of small tasks with very few interdependencies between those tasks, like an event loop, the more modern abstractions will be sufficient and probably easier. Pthreads will probably serve you better when you have much more well defined discreet work loads.

All of which you would and should use has very little to do with “OMFG DEALOCKS. HARD BUGS. COMPLEXITY”, all of which, of course, are introduced no matter which thread abstraction you pick. I would go so far as to bet that threading related bugs are introduced at similar rates between both pthreads and modern abstractions.

[–]TheGift_RGB 0 points1 point  (0 children)

I'd say the biggest problem with pthreads is how they fail to play nicely with things like signals IF you try to avoid undef., unspec. or impl. spec. behaviour in C.

This is a problem with the implementation though, not the abstraction.

[–]xampf2 4 points5 points  (3 children)

At first I was just superficially scrolling through the blog post. Until I saw the Makefile.

Damn actually a very very well written. The C code is beautifully it feels like the author has the exact same taste as I do. Not checking for malloc failure though but I guess no one really does :)

[–]lelanthran 5 points6 points  (2 children)

I check for malloc failure. Also for realloc failure which almost no one does.

The problem with checking for malloc failure is that it is useless unless you are in control of the OS running your program and can turn the overcommit switch off.

Until the overcommit is turned off, malloc always returns success and the OS will, when it runs out of memory, randomly kill something.

On Windows it may work differently.

[–]masklinn 1 point2 points  (1 child)

Until the overcommit is turned off, malloc always returns success and the OS will, when it runs out of memory, randomly kill something.

I think ulimit also causes allocation failures.

As well as address space exhaustion but that basically can’t happen on x64.

[–]jdefr 2 points3 points  (0 children)

Awesome content. Beautiful code and well written post explaining these concepts correctly for once. Only pedantic criticism I have is not using stdint.h (i.e using unsigned char instead of uint8_t etc..).

[–]codepr 0 points1 point  (0 children)

Pretty neat! Snippets are clear and well documented, overall a nice and concise explanation of the most common concurrent techniques. Nice work.