Live data from Hacker News

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

codemines.blogspot.com

51–60 of 129 posts

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

#51

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…

The D programming language has a 'pure' annotation which can be applied to functions. This enables the compiler checking that the function does not read or write any global mutable state, including checking the functions called. After using it for a while, it's amazing how much global variables tend to creep unannounced into code :-)

> The D programming language has a 'pure' annotation which can be applied to functions. This enables the compiler checking that the function does not read or write any global mutable state, including checking the functions called.

Are foreign calls assumed to be non-pure? Can they be marked pure in the case that the foreign (likely C) function doesn't reference global mutable state?

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

#52

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…

> 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. That's not true. In Rust you can have globals, but you have to declare the synchronization semantics for every global when you do. (That is, they have to be read only, or thread…

> you have to declare the synchronization semantics for every global when you do. (That is, they have to be read only, or thread local, or atomic, or protected by a lock.)

That doesn't sound like it helps you determine which one of those is appropriate. So it seems rather like a system that will lead to unexpected bottlenecks when you parallelize. (Somebody deep inside the stack arbitrarily decided locking was the most appropriate - now you've got a contended lock or a potential lock ordering bug later on.)

Granted it does seem like it allows for more reasonable defaults than a default-unsafety policy.

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

#53
post #26

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…

> lack of thread local storage is not an issue We've had it since C++11. http://en.cppreference.com/w/cpp/language/storage_duration

I think android ndk still barfs on c++11 tls and the earlier language extensions that came before it like __thread. It's not uncommon to be working with language implementations that are missing things like that. (I remember MS's version of it produced binaries that would not run on XP - maybe less important today but I had a run-in with that circa 2009.)

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

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

Can't upvote this enough. If you are using spinlocks because "mutexes are slow", please reconsider since the contended case makes much more sense with mutexes than spinlock, and the uncontended case is exactly the same.

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

#55

Earlier quoted context omitted.

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.

> Outside of hard realtime code, there's zero reason to use spin locks. On some common architectures, releasing a spin lock is cheaper than releasing a mutex.

On all architectures, releasing a mutex requires at least a branch (to see if you need to wake up sleeping threads) that you don’t need with a pure spinlock.

But if you don’t have a guarantee the lock owner won’t be preempted, well, spinning for a whole timeslot is quite a bit more expensive…

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

#56
post #14

Earlier quoted context omitted.

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.

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

That is just not true. You _must_ use them in the case where the kernel is non-preemptable. Additionally, if the locked resource is held for a very short time, a spin lock is likely a more efficient choice than a traditional mutex.

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

#57

Earlier quoted context omitted.

The D programming language has a 'pure' annotation which can be applied to functions. This enables the compiler checking that the function does not read or write any global mutable state, including checking the functions called. After using it for a while, it's amazing how much global variables tend to creep unannounced into code :-)

> The D programming language has a 'pure' annotation which can be applied to functions. This enables the compiler checking that the function does not read or write any global mutable state, including checking the functions called. Are foreign calls assumed to be non-pure? Can they be marked pure in the case that the foreign (likely C) function doesn't reference global mutable state?

> Are foreign calls assumed to be non-pure?

Yes.

> Can they be marked pure in the case that the foreign (likely C) function doesn't reference global mutable state?

Yes. Here's an example:

https://github.com/dlang/druntime/blob/master/src/core/stdc/...

It's true that the C Standard does not actually guarantee that they don't access mutable global state, but in practice they don't. We're not aware of one that does, and don't know why anyone would write one that does.

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

#58
post #55

Earlier quoted context omitted.

> Outside of hard realtime code, there's zero reason to use spin locks. On some common architectures, releasing a spin lock is cheaper than releasing a mutex.

On all architectures, releasing a mutex requires at least a branch (to see if you need to wake up sleeping threads) that you don’t need with a pure spinlock. But if you don’t have a guarantee the lock owner won’t be preempted, well, spinning for a whole timeslot is quite a bit more expensive…

Spin locks are a tough sell in a preemptable context. Say you have two processes that share some memory location. They both briefly access it for a very short time, so you protect it with a spin lock. Well, what happens in the case when one of the threads is preempted while holding the lock? The other thread would try to aquire it, and just spin for its entire timeslot. No bueno. When you call spin_lock() in the kernel it actually disables preemption until you call spin_unlock() to avoid this. You can't disable preemption from userspace. There might be a use for a spin lock if you have a process that is SCHED_RR, but I haven't seen it.

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

#59
post #55

Earlier quoted context omitted.

On all architectures, releasing a mutex requires at least a branch (to see if you need to wake up sleeping threads) that you don’t need with a pure spinlock. But if you don’t have a guarantee the lock owner won’t be preempted, well, spinning for a whole timeslot is quite a bit more expensive…

Spin locks are a tough sell in a preemptable context. Say you have two processes that share some memory location. They both briefly access it for a very short time, so you protect it with a spin lock. Well, what happens in the case when one of the threads is preempted while holding the lock? The other thread would try to aquire it, and just spin for its entire timeslot. No bueno. When you call spin_lock() in the kern…

http://bit.ly/2urhLeM

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

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

true. also, to hell with this article. i don't understand how people can wrangle with AI problems, crypto problems, even more mundane problems and somehow manage to fuck up threading. it barely ranks as a real problem for any competent coder IMO. i -almost- always do my own low level synchronization. it took a while and many errors to get comfortable with it, but in 2017 i think it's really barely worth writing about.
Post reply on HN