Live data from Hacker News

C++20: Building a Thread-Pool with Coroutines

blog.eiler.eu

31–40 of 63 posts

Re: C++20: Building a Thread-Pool with Coroutines

#31
post #26

Earlier quoted context omitted.

Most of that boilerplate will be hidden in the libraries which use it. Unless you are a library author I don’t know why you would care about the boilerplate-like elements from the standard— you will only use co_yield and co_await.

C++ compilers are famous for their cryptic error messages. Standard Libraries are the reason.

Lack of concepts was the reason, it will only get better now.

Re: C++20: Building a Thread-Pool with Coroutines

#32
post #11

Earlier quoted context omitted.

also the memory management model in c++ is much more complex - most other languages just use garbage collection to deal with reference lifetimes

garbage collection is one of the abstractions that can interfere with performance. it's out of the question for real time contexts, for example.

Depends,

https://www.ptc.com/en/products/developer-tools/perc

https://www.aicas.com/wp/products-services/jamaicavm/

On the other hand there is real time where even malloc() is forbidden.

https://en.m.wikipedia.org/wiki/MISRA_C

Re: C++20: Building a Thread-Pool with Coroutines

#33

Earlier quoted context omitted.

It still boggles the mind that they made it so hard to use this stuff in terms of boilerplate. Hopefully that will all be abstracted into a library that handles io, networking, multiprocessing and synchronization so most of us can just focus on writing the bits that do stuff. But I will never understand how the std maintainers could not manage to do this when every other language is doing async await support in their…

I think the reason it's like this is because the C++ maintainers are super focused on noticing whenever there is a choice to be made, and being careful not to make it for you. Given the option between foisting situationally bad performance on you and foisting lots of syntax and interface complexity on you, they always choose the latter. Which I suppose makes sense: C++ niche is that it's the Big Gun you pull out when…

> I think the reason it's like this is because the C++ maintainers are super focused on noticing whenever there is a choice to be made, and being careful not to make it for you

If you think that's the case, explain why I can't decide I want to pass an argument to a function in a register:

https://stackoverflow.com/q/58339165/1593077

Also, modern C++ has actually made it possible to write much more elegant code, for many delicate tasks, without sacrificing the performance benefits. So a convenient default doesn't necessarily have to contradict non-opinionated nature.

Re: C++20: Building a Thread-Pool with Coroutines

#34

I used similar thing, baked on top of cppcoro library (wonderful thing). My application is heavily threaded with hundreds of thousands of short-lived micro-tasks, it's interpreter of highly-parallel expressions, and values are large matrices containing expressions, so it's highly parallelizable. I moved to C++ coroutines from composable futures (CF) library that had few thread pool implementations if memory serves (a…

> chinese libgo

I believe you mean this one? :

libgo -- a coroutine library and a parallel Programming Library

https://github.com/yyzybb537/libgo

(no information about the main contributor unfortunately)

Re: C++20: Building a Thread-Pool with Coroutines

#35

I'll admit I find coroutines difficult to grok. It seems to me that 'callback hell' is turning into 'coroutine hell'. The only plausible use-case I can see is enabling functionality similar to that of Python's `yield`. Does threadpool::thread_loop() not have to check if the popped coroutine is suspended before attempting to resume it? Are they really more efficient than normal callbacks when doing async?

For what it's worth Python's yield pretty much is a coroutine, as it has a (very rarely used) feature that allows information from the caller to be passed back to the generator. The c++ implementation seems closer to lisps 'call with current continuation', though as far as I can tell all implementations achieve more or less the same thing (though thread safety might vary among the options). Actually continuation pass…

> as it has a (very rarely used) feature that allows information from the caller to be passed back to the generator.

The Twisted library encouraged heavy use of this before Python implemented async/await.

https://twistedmatrix.com/documents/current/core/howto/defer...

Re: C++20: Building a Thread-Pool with Coroutines

#36

I'll admit I find coroutines difficult to grok. It seems to me that 'callback hell' is turning into 'coroutine hell'. The only plausible use-case I can see is enabling functionality similar to that of Python's `yield`. Does threadpool::thread_loop() not have to check if the popped coroutine is suspended before attempting to resume it? Are they really more efficient than normal callbacks when doing async?

There are a lot more possibilities. The reason why they are so complicated is simply to give the library developers all possible options. This features is afaik something targeted at them, so that boost, asio and others can implement powerful solutions without language restrictions.

The only way to enqueue a coroutine is to call schedule() within a co_await statement/expression. In this process the coroutine is suspended. Therefore there should not be any coroutine within the queue, which we cannot immediately resume.

I'm afraid I don't have any numbers available to compare coroutines with other approaches. But nevertheless in my opinion coroutines are benefitial because they keep their state (the stack frame, local variables) alive. If you use callbacks you would have to handle all these things yourself. Think about a generator for a sequence of numbers. You would have to store at least the counter variable manually. With a coroutine this happens automatically.

Re: C++20: Building a Thread-Pool with Coroutines

#37
post #3

Really nice write up! I'm excited to see more coroutine tutorials and guides come out, I think this C++20 feature has huge potential to make C++ easier to use over the next decade. I will also say I was a bit surprised to see libcoro linked in the article! I'm glad you found it useful but I need to give most of the credit to Lewis Baker's cppcoro as well -- I learned most of what I implemented into libcoro from his f…

I completely agree!

Why not benefit from Lewis's work on cppcoro? He obviously has thought through the most important issues one would otherwise also stumble across. Unfortunately cppcoro doesn't look like it is actively maintained, which his why I was looking for other implementations. I'm excited to see how your library will progress in the future!

Re: C++20: Building a Thread-Pool with Coroutines

#38
post #19

Earlier quoted context omitted.

If things could be "consigned to history" by C++ adding more features, there'd hardly be any other languages left! It has all the features. That's its biggest problem.

Noo, it's missing something basic: struct introspection. Unlike almost every other modern language, it's not possible to write a generic "ToJson" or "ToString" that will work for any struct.

Not sure whether that's a sarcastic commentary or your just not aware, but C++ will, of course, also get (static) reflection

https://en.cppreference.com/w/cpp/keyword/reflexpr

Re: C++20: Building a Thread-Pool with Coroutines

#39

I used similar thing, baked on top of cppcoro library (wonderful thing). My application is heavily threaded with hundreds of thousands of short-lived micro-tasks, it's interpreter of highly-parallel expressions, and values are large matrices containing expressions, so it's highly parallelizable. I moved to C++ coroutines from composable futures (CF) library that had few thread pool implementations if memory serves (a…

Having only briefly looked through the code base of libgo. It looks like they use boost::context, which is the only good stackful coroutines implementations I've come across. Not being familiar with your project I'm slightly confused about the statement of "hundreds of thousands of short-lives micro-tasks". This is usually a no-go in case of stackful coroutines, as you would waste too much memory as well as have a lot of overhead.

Regarding your debugging issues. I'd be surprised if this doesn't improve over the next year or two. Clang afaik isn't even fully compatible with the final version of coroutines yet. Microsoft has done a lot of work on the compiler itself. I'd assume that Visual Studio will likely ship improvements once they release VS2022(?). Of course these are only guesses from my side.

Summing it up it sounds to me like you suffered from the curse of being an early adopter. It would be interesting to see if you'd have less issues once tooling and compiler support has improved enough.

Re: C++20: Building a Thread-Pool with Coroutines

#40
post #31
post #26

Earlier quoted context omitted.

C++ compilers are famous for their cryptic error messages. Standard Libraries are the reason.

Lack of concepts was the reason, it will only get better now.

So far as I can see in 2026 the C++ programmers will be assuring us that (some feature from C++26) is going to fix all the awful clag in the C++23 programs which, in turn, offered (some feature from C++23, maybe it's a simpler exception mechanism) but alas instead created more clag, despite their promise to clear up the mess from C++20...

I am an old man, and so I remember when left and right every C++ programmer was excited about how the Standard Template Library was going to make everything OK and those of us who were still jeering would be writing C++ soon. How did that go?

Post reply on HN