4 ms·
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 ch
by andreasgonewild 9y ago
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_cpp_chan.md https://github.com/andreas-gone-wild/blog/blob/master/diy_cp...
- to3m 9y agoThis 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<thread>. The C++ thread library works on Windows, too...
- comex 9y ago> I'm not actually sure that the C++ library does anything that pthreads doesn't There’s std::atomic, which didn’t have a standardized equivalent in pthreads. In lieu of that you’d see some ad-hoc combination of GCC builtins, OS-specific functions, and `volatile`, with the result often not guaranteed to work on architectures other than x86 (if at all). Compared to that, std::atomic is both more flexible and easier to get right. The C ‘backport’, stdatomic.h, is also available on most platforms these days...
- andreasgonewild 9y agoI was thinking about mostly about atomics, which aren't covered by pthreads; and I can't remember shared mutexes being supported either.
- ridiculous_fish 9y agoUnfortunately std::thread is not as capable as pthreads. For example, std::thread has no facilities for controlling the stack size or signal mask. Whenever I use channels, I find I need them to synchronize with each other. For example, I have a Go data structure with a write channel and a separate read channel; how do I avoid a read-after-write hazard? The simplest solution is to make them the same channel that ships closures, to ensure requests are processed in-order. But then why not just make all channels ship closures, like libdispatch...
- shaklee3 9y agoYou can get the underlying pthread pointer if you want.
- ridiculous_fish 9y agoUnfortunately pthread attributes need to be set at creation time, so by the time you have a pthread pointer it's too late.
- to3m 9y agopthread_sigmask always operates on the current thread.
- ridiculous_fish 9y agoThe 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.
- to3m 9y agoInteresting point about the stack size! As for the signal mask, I'm pretty sure you can just set that using pthreads, and it will apply to the current thread. This is certainly true for the pthreads thread name, which is as deeply as I've investigated myself... the C++ threads library isn't magic. It's just a wrapper round what you'd expect.
- Matthias247 9y agoChannels like the one in the link are pretty easy to create. However that's more like Javas BlockingQueue than like Go channels. The power of Gos channels is in "select", which enables a lot more sophisticated synchronization mechansism then just getting data from thread A to B. E.g. waiting for events from multiple sources or cancellation support. Building channels with select functionality is a lot harder. An interesting thing is the equivalent of pthreads on windows (WinAPI synchronization primitives) actually provides something which has some similarity with select out of the box: WaitForMultipleEvents, which is also quite powerful. However that is also a still a lot harder to work with than Go's channels, since there are additional sources for errors like HANDLE invalidation, which you can't have in Go where channels are garbage collected references.
- andreasgonewild 9y agoWhat 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.
- marcosdumay 9y agoSelect 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?
- xfer 9y agotimerfd?
- andreasgonewild 9y agoAre 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.