Live data from Hacker News

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

codemines.blogspot.com

11–20 of 129 posts

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

#11
post #4

> While standardization and support for [threaded] APIs has come a long way, their use is still predominantly restricted to system programmers as opposed to application programmers. One of the reasons for this is that APIs such as Pthreads are considered to be low-level primitives. Conventional wisdom indicates that a large class of applications can be efficiently supported by higher level constructs (or directives)…

Since OMP Tasks it is kinda useful for non-numerical non-trivial applications as well, though still kinda... odd. Odd but neat.

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

#12
post #4

> While standardization and support for [threaded] APIs has come a long way, their use is still predominantly restricted to system programmers as opposed to application programmers. One of the reasons for this is that APIs such as Pthreads are considered to be low-level primitives. Conventional wisdom indicates that a large class of applications can be efficiently supported by higher level constructs (or directives)…

Yes, every time I hear people talking about how evil or difficult threads are, I just think back to my frequent use of OpenMP. It is really quite easy to take a single-threaded program and make it multithreaded with OMP -- so long as the jobs only read, and do not write shared state.

Usually I will write a program that does the following:

1. Initialize global read-only data structures

2. Parallelize jobs across STDIN lines (or whatever)

3. Output results within a #pragma omp critical block

It works wonders, and is literally 5 additional lines of code to make a single-threaded program multithreaded with OMP. But only for some types of program. The concept is very similar to what GNU parallel does.

In short, threads are not the problem per se, they are just the wrong tool for the job if you have a multiple-readers multiple-writers situation. Message passing, databases, or something else are more appropriate in those cases. But you will pry my read only shared memory space out of my cold, dead hands.

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

#13
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…

Is there a good message passing library for C++? Sounds like something for the stl to include.

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

#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 when you don't have other options (e.g. interrupt handler). Anything else is just burning CPU cycles for nothing.

Mutex and condition variables (emphasis on the latter) are much more useful than spinlocks and atomics for general multithreaded programming.

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

#15

There is no need to use raw pthreads in modern C++, it comes equipped with a much more convenient and capable standard library module. I prefer working with channels, which are still missing from the library; but they are trivial to add: https://github.com/andreas-gone-wild/blog/blob/master/diy_cp...

This is good advice and should never have attracted a downvote!

I'm not actually sure that the C++ library does anything that pthreads doesn't - maybe std::lock, perhaps? - but it's more convenient to use (and it's not like pthreads is bad to start with...), and the pieces work well and fit together quite nicely. Some good use of move semantics. unique_lock is neat and you can do stuff like vector.

The C++ thread library works on Windows, too...

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

#16
When I think about hard problems, I like to look at projects I feel handle these problems well. Having worked in the Chromium code base for some time now, I really appreciate their approach to threading. So much so, I really wish they would distribute their base/threading module as its own project.

https://chromium.googlesource.com/chromium/src/+/lkcr/docs/t...

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

#17
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 all of their state as input, and return all results as output, without modifying ant kind of global state. You can run any number of these in parallel without thread safety issues, or locks. When using multiple threads with shared data, you have to protect it with locks, but I generally use a single thread to access data of this sort which produces work for other threads to do, which can be queued or distributed any other way. Producer/consumer queues show up a lot in good designs, and your single-threaded choke points are usually a producer or a consumer, which allows thread fan-in or fan-out. (As a side note, Go really got this right with channels).

What leads to problems in threaded C++ programs is unprotected, shared state. Some C++ design patterns make life particularly hard, such as singletons, which are just a funny name for global variables. C++ gives you lots of ways to make something global accidentally - static member variables, arguments by reference, for instance.

True C++ hell is taking a single threaded C++ program and making it multi-threaded after the fact, but that's hell in any language which allows you to have globals of any sort and doesn't perform function calls within some kind of closure.

The article in this post is being a little reductionist. You don't need to pick a threading model - some of your threads can pass messages, others can use shared data, all in the same program. The lack of thread local storage is not an issue, because you partition the data so that no two threads are working on the same thing at the same time.

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

#18

So to check, I googled C++11 threads memory model, and it[0] looks like his main complaint isn't helped by C++ 11 threads, as they essentially allow shared state too. They are also a thin veneer over the OS threads, for unix types, pthreads I imagine. [0] http://en.cppreference.com/w/cpp/language/memory_model

Yeah, I don't know if there's ever going to be a portable way to enforceably "disallow" the sharing of state between threads in C++. For straightforward cases, the SaferCPlusPlus library provides an easy way to "wrap" any object so that access from different threads is safely controlled[1].

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#asynchronou...

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

#19
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…

You have to be careful with those things - for instance, you have to special case whether you'r on a single CPU or multiple CPU system, because a spin lock will block forever in a non-preemptive context, such as the kernel.

Outside of hard realtime code, there's zero reason to use spin locks.

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

#20
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…

Is there a good message passing library for C++? Sounds like something for the stl to include.

I know coworkers that speak well of ZeroMQ:

http://zeromq.org

Post reply on HN