Live data from Hacker News

Hell is a multi-threaded C++ program (2006)

codemines.blogspot.com

71–80 of 129 posts

Re: Hell is a multi-threaded C++ program (2006)

#71

Earlier quoted context omitted.

So, functional programming then?

I'm tired of thinking this in my head but - skimming through doug lea concurrency articles: FP - thread safe C: pure functions, shared nothing: FP - comment above: FP at what point will people start to call it what it is ?

[deleted]

Re: Hell is a multi-threaded C++ program (2006)

#72
Good article by the creator [0] on how Lyft's relatively new L4-7 proxy called Envoy [1] handles multi-threading at https://medium.com/@mattklein123/envoy-threading-model-a8d44.... There are now more people at Google contributing to Envoy than Lyft.

0. https://twitter.com/mattklein123/

1. https://lyft.github.io/envoy/

Re: Hell is a multi-threaded C++ program (2006)

#73
post #63

I've been writing massively threaded C++ code since the 1990's, so I can comment with some serious experience here. My code used to run on 256CPU SGI's and had high cpu utilization across all of them. When designing C++ code for threading, you have to keep a few things in mind, but it's not particularly harder than on other languages with thread support. You generally want to create re-entrant functions which pass al…

I am not as experienced as you are and I don't even know the term re-entrant functions but accidentally this is how I am now designing programs, mostly writing self contained functions that don't alter any global state. This approach has made my programming life hell because I am finding it incredibly hard to get rid of the old shared variables habit. What I have experienced is that shared data access is more or less…

Re-entrant is basically what you said, self-contained functions that don't depend on external state. The "re-entrant" part just means that, basically, the function can be "re-entered." If it gets interrupted in the middle of execution, it will still produce the same output no matter what, no matter how long it sleeps for.

Re: Hell is a multi-threaded C++ program (2006)

#74
Generally, do not use raw threads. They are a building block for higher level abstractions like task queues, pipelines, futures... which lend themselves to higher level algorithms like your sorts, filters, find, map, reduce, map_reduce...

C++17 gets a lot of this with much of the algorithms header getting parallel/vectorized versions. But it doesn't have a task stealing work queue or something like then to pass the value when it completes. Boost has a version now that does though and this lets you have the next function called when done instead of waiting and blocking.

But if you spend your time in the thread zone you are probably putting too much thought into threading and not the problem you are solving. Plus, using a task queue can yield really good results for lower level algorithms.

Re: Hell is a multi-threaded C++ program (2006)

#75

Earlier quoted context omitted.

What is even more fundamental and useful than select is non-blocking reads (which the implementation I posted supports), once you have that you can write your own select. It's not magic, select has to traverse the list of channels just like any other code. The only reason it feels like magic in Go is that it's the only way to read a channel without blocking.

Select is a kernel level interface. I don't know how it's implemented at the kernel, but there is no technical reason why it can't follow from an interruption to an array index and a file descriptor without ever passing through a list. Besides, how do you block in user space when there is nothing to read?

timerfd?

Re: Hell is a multi-threaded C++ program (2006)

#76
post #69

I've been writing massively threaded C++ code since the 1990's, so I can comment with some serious experience here. My code used to run on 256CPU SGI's and had high cpu utilization across all of them. When designing C++ code for threading, you have to keep a few things in mind, but it's not particularly harder than on other languages with thread support. You generally want to create re-entrant functions which pass al…

Obviously it is possible to write threaded C++ programs. And there are experienced people like you who can do it well, with enough discipline, good design, and so on. But I think the point of the article is that for most programmers it is very easy to make mistakes and shoot themselves in the foot with threads and shared memory. It could be even something like using a 3rd party library where it's initialization conte…

I think the OP's attitude is still correct. Threaded programs are hard. It takes experience, discipline, and good design. There is no band-aid for that. The technology is helping with things like local storage, built in actor models, borrow checkers, etc. but those are only helping the design aspect. It still takes discipline, like knowing to not mix up async callbacks with/across threads. You are basically writing your own little kernel, and writing a kernel is hard, but once you know the rules it can be done.

Re: Hell is a multi-threaded C++ program (2006)

#77
post #14
post #2

I've found message passing and thinking in transactions are pretty good architectural patterns for maintaining ones sanity. Message queues with spinlocks for performance critical code (mutexes are slow). The biggest sin generally is to disregard the overhead caused by thread management and thinking more threads makes the sofrware run faster. I've seen people try to parallellize a sequential program by just spawning m…

An uncontended mutex is just as fast as a spinlock (on modern operating systems using a futex). It takes about 25 nanoseconds to lock it. The difference is when there's contention. A spinlock will burn CPU cycles but a mutex will yield to another thread or process (with some context switch overhead). A spinlock should only be used when you know you're going to get it in the next microsecond or so. Or in kernel space…

And a mutex that you never take is cheaper than one that you do. Taking the (f)mutex is fast but any context switch will be brutal if you're really using threading to increase your performance.

That said I'm used to situations where we're pinning thread affinity to specific cores and really trying to squeeze out what you can from fixed resources.

Re: Hell is a multi-threaded C++ program (2006)

#79

Earlier quoted context omitted.

What is even more fundamental and useful than select is non-blocking reads (which the implementation I posted supports), once you have that you can write your own select. It's not magic, select has to traverse the list of channels just like any other code. The only reason it feels like magic in Go is that it's the only way to read a channel without blocking.

Select is a kernel level interface. I don't know how it's implemented at the kernel, but there is no technical reason why it can't follow from an interruption to an array index and a file descriptor without ever passing through a list. Besides, how do you block in user space when there is nothing to read?

Are you saying they are allocating a separate file-descriptor for each channel just to be able to select? I guess you could do that if you wanted to but it's far from the first thing I would try. I remember reading an article on golang about select and having to traverse the list, but I don't really have the motivation to dig deeper right now.

Looping with unblocking reads is plenty fast enough though.

As for waiting on any event without select, adding an optional condition-variable pointer to each channel that is pinged when data arrives is the easiest approach I can think of.

Re: Hell is a multi-threaded C++ program (2006)

#80
post #45

Earlier quoted context omitted.

You can get the underlying pthread pointer if you want.

pthread_sigmask always operates on the current thread.

The usual technique is to set the pthread sigmask and then spawn the thread, to avoid the obvious race. But it's risky to assume that `std::thread` won't manipulate the sigmask by itself.
Post reply on HN