boostorg / coroutine2 Goto Github PK
View Code? Open in Web Editor NEWBoost.Coroutine2
Boost.Coroutine2
Following program crashes when compiled with Visual Studio 2015 Update 3, win32, release build. But does not in debug build or if cout is uncommented. Boost version 1.66
int main() {
typedef boost::coroutines2::coroutine<void> coro_t;
coro_t::pull_type coro([&](coro_t::push_type& yield) {
//std::cout << "111";
});
return 0;
}
We're currently bumping boost from 1.55 to 1.72, replacing coroutine for coroutine2 as a result.
Our code uses coroutines extensively and after the bump some of our code and unit tests are no longer working.
b2.exe link=shared threading=multi runtime-link=shared extern-c-nothrow=off address-model=64
Here is a gtest test case reproducing the problem.
TEST(coroutine, boost_test_coroutine2_exceptions) {
using CoroType = boost::coroutines2::coroutine<void>;
using Caller = CoroType::push_type;
using Coro = CoroType::pull_type;
Coro coro_throw_within_catch(
[&](Caller& c) {
// Resume execution in main
c();
// 1. Throw an exception
// 2. Catch it
// 3. In catch handler, start a new coro
// 4. throw an exception
//
// Expected behavior when coro() is called:
// A std::exception is thrown
// What I see:
// Program ends in abort() since it finds no exception handler
try {
throw std::exception("Bam!");
}
catch (std::exception&) {
Coro empty_coro([](Caller&) {});
}
throw std::exception("Boom");
});
EXPECT_THROW(coro_throw_within_catch(), std::exception);
}
If the Coro empty_coro([](Caller&) {});
is moved two lines down (out of the catch statement), there is no crash.
The test requirements does not include requirements of context fibers. On 32bit MinGW thread_local
is banned in boost because __cxa_thread_atexit
crashes with them, resulting in not building fibers (the cxx11_thread_local
requirement), but the test does not have that requirement and fails at linking. It either should be fixed in context by providing pseudo fiber library that will have usage requirements or just mirroring fiber build requirements on tests here.
How coroutine2 communicates between coroutines?
BoostCoroTest.zip
I've attached configured sample which crashes (*.sln and source file). Can be reproduced if this solution compiled on Release & x86 configuration. /O2 and /Ob2 are enabled, all other options are disabled. If /GL (in VS it calls: "Whole Program Optimization") is enabled all works fine.
I used Boost.Coroutine2 from boost 1.65.1.
see #31
the change introduced now doesn't allow
using namespace boost::coroutines2;
auto my_coro = coroutine<int>::pull_type{
[](coroutine<int>::push_type& yield) {
for (int i = 0; i < 5; ++i) {
yield(i);
}
}
};
for (auto i : my_coro) {
// ^ ambiguous call to 'begin', ambiguous call to 'end'
std::cout << i << std::endl;
}
tested with gcc 10.3.0, using --std=c++17; and msvc also using c++17 mode
using boost 1.76.0
see also #39
Issue description:
Boost\libs\coroutine2 failed to build due to error C2668 on MSVC. Could you please take a look? We ues boostorg/boost@ea9f9fb from Boost master branch. from Boost master branch.
Build step:
Error info:
test_coroutine.cpp
libs\coroutine2\test\test_coroutine.cpp(538): error C2668: 'std::begin': ambiguous call to overloaded function
.\boost/coroutine2/detail/pull_coroutine.hpp(301): note: could be 'boost::coroutines2::detail::pull_coroutine::iterator std::begin(boost::coroutines2::detail::pull_coroutine &)' [found using argument-dependent lookup]
with
[
T=int
]
.\boost/coroutine2/detail/pull_coroutine.hpp(285): note: or 'boost::coroutines2::detail::pull_coroutine::iterator boost::coroutines2::detail::begin(boost::coroutines2::detail::pull_coroutine &)' [found using argument-dependent lookup]
with
[
T=int
]
libs\coroutine2\test\test_coroutine.cpp(539): note: while trying to match the argument list '(boost::coroutines2::detail::pull_coroutine)'
with
[
T=int
]
libs\coroutine2\test\test_coroutine.cpp(538): error C2668: 'std::end': ambiguous call to overloaded function
.\boost/coroutine2/detail/pull_coroutine.hpp(307): note: could be 'boost::coroutines2::detail::pull_coroutine::iterator std::end(boost::coroutines2::detail::pull_coroutine &)' [found using argument-dependent lookup]
with
[
T=int
]
We are in the process of making B2 build changes to all of the B2 build files
to support "modular" consumption of the Boost Libraries by users. See this list
post for some details: https://lists.boost.org/Archives/boost/2024/01/255704.php
The process requires making a variety of changes to make each Boost library
independent of the super-project structure. But the changes do not remove the
super-project structure or the comprehensive Boost release. The changes make
solely make it possible, optionally, for users, like package manages, to easily
consume libraries individually.
Generally the changes include:
Some examples of such changes:
We are asking how you would like us to handle the changes. We would prefer if
you allow the owners of the Boost.org GitHub project to make changes to B2
build files, as needed, to accomplish the changes. But understand
that you may want to manage the proposed changes yourself.
We previously sent emails to all known maintainers to fill out a form with their
preference. We are contacting you in this issue as we have not gotten a response
to that email. You can see the ongoing responses for that form and the responses
to these issues here https://github.com/users/grafikrobot/projects/1/views/6
We are now asking if you can reply directly to this issue to indicate your
preference of handling the changes. Please supply a response to this question
and close the issue (so that we can verify you are a maintainer).
How would you like the build changes to be processed?
Also please indicate any special instructions you want us to consider. Or other
information you want us to be aware of.
Thanks you, René
Hello,
the documentation says:
Code executed by coroutine-function must not prevent the propagation of the detail::forced_unwind exception
... and the subsequent example propagates boost::coroutines2::detail::forced_unwind.
However, simple grep over boost/coroutine2 sources shows boost::coroutines2::detail::forced_unwind is not referenced anywhere except the place it was declared.
Pull/push coroutines implementation catches and re-throws the boost::context::detail::forced_unwind instead.
So which exception a user code should propagate?
Background
I've patched boost.asio to use boost.coroutine2 for our product in order to allow our code to be instrumented with ASan. Both the code and ASan instrumentation seem to work after the migration however one of our unit tests fails. It explicitly throws boost::coroutines2::detail::forced_unwind from the coroutine to check whether the exception is propagated correctly by our code and expects the coroutine collapses. This worked perfectly with boost.coroutine (v1), but crashes with unhandled exception for boost.coroutine2.
Could you please add some guidance on how to select between coroutine and coroutine2 in README or manual? Is coroutine deprecated? No reference is made from either library to the other. Whether they are successors, alternatives... Some clarification would really help.
Coroutine2 does not seem to work under cygwin.
This code:
https://github.com/NixOS/nix/blob/2.3.9/src/libutil/serialise.cc#L188
crashes right away with a quite misterious backtrace on Access Violation.
I don't know whether this is a problem of coroutine2 or context. https://github.com/boostorg/context
It appears that somehow the interface of Boost.Coroutine is reflected in the Boost.Coroutine2 documentation.
Examples:
http://www.boost.org/doc/libs/1_62_0/libs/coroutine2/doc/html/coroutine2/coroutine/asymmetric/push_coro.html
http://www.boost.org/doc/libs/1_62_0/libs/coroutine2/doc/html/coroutine2/coroutine/asymmetric/pull_coro.html
Hello.
VS2019 v. 16.11.2 , VS2022 17.0.0 RC
OS Windows 10 x64
boost 1.76
in file <boost/coroutine2/detail/wrap.hpp>, in class wrapper
boost::context::fiber operator()( boost::context::fiber && c) { return boost::context::detail::invoke( std::move( fn1_), fn2_, std::forward< boost::context::fiber >( c) ); }
boost::context::detail::invoke uses std::result_of.
std::result_of was removed from the C++17 standard.
Test program won't compile
With Boost.Coroutine it is possible to create a default constructed coroutine-object and get not-a-coroutine, which e.g. later can be swapped with a real coroutine. With Boost.Coroutine2 the default constructor is not available, and construction from a nullptr of type control_block* is private.
Is there any specific reason for not allowing default-created coroutines?
Because push_type and pull_type are inner types they are non-deducible which makes it hard to build generic algorithms on top of coroutines.
For example given two coroutines that produce sorted values one can merge them into a single coroutine.
template <class T>
using Stream = boost::coroutines2::coroutine<T>::pull_type;
// T cannot be deduced here.
template <class T>
Stream<T> Merge(Stream<T> s0, Stream<T> s1);
If we have coroutine_pull_type<T>
deduction works.
The Coroutine2 docs state (doc/stack.qbk)
Running programs that switch stacks under valgrind causes problems. Property (b2 command-line)
valgrind=on
let valgrind treat the memory regions as stack space which suppresses the errors.
However, I searched through the source code and I cannot find the text "valgrind" anywhere. Is this still a supported feature?
Thanks
Given webassembly currently doesn't have couroutine support, being able to use boost fibers from emscripten would be awesome!
According to the documentation:
But what happens if:
push_type coro([](pull_type&){ return; });
bool(coro) == true
(or: begin(coro) != end(coro)
) so the user would like to perform coro(value_of_T)
(or: *begin(coro) = value_of_T
)It seems the value will be lost.
(Edit: sorry for the mistake, it's the last value that will always be lost if the output range is not infinite.)
#include<boost/coroutine2/all.hpp>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<utility>
int main()
{
typedef boost::coroutines2::coroutine<std::string> coro_t;
struct FinalEOL {
~FinalEOL() {
std::cout << std::endl;
}
};
const int num = 5, width = 15;
coro_t::push_type writer(
[&](coro_t::pull_type& in) {
//// finish the last line when we leave by whatever means
//FinalEOL eol;
// pull values from upstream, lay them out 'num' to a line
//for (;;) {
// for (int i = 0; i < num; ++i) {
// // when we exhaust the input, stop
// if (!in) return;
// std::cout << std::setw(width) << in.get();
// // now that we've handled this item, advance to next
// in();
// }
// // after 'num' items, line break
// std::cout << std::endl;
//}
});
std::vector<std::string> words{
"peas", "porridge", "hot", "peas",
"porridge", "cold", "peas", "porridge",
"in", "the", "pot", "nine",
"days", "old" };
//std::copy(begin(words), end(words), begin(writer));
// safe version of std::copy that takes care of end(dest)
auto [words_it, writer_it] = std::pair{ begin(words),begin(writer) };
for (; words_it != end(words) && writer_it != end(writer); ++words_it, ++writer_it)
{
*writer_it = *words_it;
}
// print remaining words; the first word is lost
for (; words_it != end(words); ++words_it)
{
std::cout << *words_it << "\t";
}
}
An applicable approach would be to resume the coroutine in begin(coro)
like https://github.com/lewissbaker/cppcoro#generatort .
Here is the current API and the imagined API:
current API:
pull_type | framework-generated push_type for pull_type | push_type | framework-generated pull_type for push_type | |
---|---|---|---|---|
constructor | enter coroutine-function | |||
operator() iterator::operator++() |
resume coroutine-function | suspend coroutine-function | ||
get() | transfer data | transfer data | ||
operator() iterator::operator=() |
transfer data, suspend coroutine-function | (first time: transfer data, enter coroutine-function) transfer data, resume coroutine-function |
imagined API:
pull_type | framework-generated push_type for pull_type | push_type | framework-generated pull_type for push_type | |
---|---|---|---|---|
constructor | ||||
start() begin(coro) |
①enter coroutine-function | ② | ⒈enter coroutine-function | ⒉suspend coroutine-function |
advance() iterator::operator++() |
⑥⑩resume coroutine-function | ④⑧suspend coroutine-function | ⒋⒏resume coroutine-function | ⒍⒑suspend coroutine-function |
get() | ⑤⑨transfer data | ⒌⒐transfer data | ||
set() iterator::operator=() |
③⑦transfer data | ⒊⒎transfer data |
Note that in the column of push_type
: if after ⒊transfer data
instead of ⒋resume coroutine-function
you ⒋abandon the coroutine
, then the value_of_T
will still be lost. But this time it is the user of API to blame, not the framework.
These are what you can do:
utility | current API | imagined API |
---|---|---|
merge pipe and source into sourcevoid(pull_type<T1>,push_type<T2>) + pull_type<T1> -> pull_type<T2> |
trivial for loop | trivial for loop |
merge pipe and source into sourceT2(T1) + pull_type<T1> -> pull_type<T2> |
trivial for loop | trivial for loop |
merge pipe and sink into sinkvoid(pull_type<T1>,push_type<T2>) + push_type<T2> -> push_type<T1> |
trivial for loop | trivial for loop |
merge pipe and sink into sinkT2(T1) + push_type<T2> -> push_type<T1> |
trivial for loop | trivial for loop |
merge source and sink and stops when either one exhaustsstd::pair<source_it_t, sink_it_t> safe_copy(source_begin, source_end, sink_begin, sink_end) |
the first value of source will be lost if sink is an empty range | trivial for loop the user will not lose the first value of source because if sink is an empty range then we have begin(sink) == end(sink) after construction and start()/begin(sink) |
It's impossible to avoid exceptions using the coroutines2 library (Boost version 1.69).
Consider this (pretty much the example) code where a coroutine gets created, used and destroyed:
#include <boost/coroutine2/all.hpp>
#include <iostream>
using coro_t = boost::coroutines2::coroutine<int>;
inline auto make_coro()
{
return coro_t::pull_type{
[](coro_t::push_type & sink) {
sink(1);
}
};
}
int main()
{
auto f = make_coro();
while(f)
{
std::cout << f.get() << "\n";
f();
}
}
Does the unwind need to happen here on the coroutine destruction? Doesn't look like it. However, the forced_unwind
exception still gets thrown. Here's the backtrace:
#0 __cxxabiv1::__cxa_throw (... <typeinfo for boost::context::detail::forced_unwind>
#1 in boost::context::detail::fiber_unwind (t=...)
at .../include/boost/context/fiber_fcontext.hpp:58
#2 in boost::context::fiber::resume()
at .../include/boost/context/fiber_fcontext.hpp:289
#3 in boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}::operator()(boost::context::fiber) (...)
at .../include/boost/coroutine2/detail/pull_control_block_cc.ipp:95
#4 in std::__invoke_impl<boost::context::fiber, boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&, boost::context::fiber>(std::__invoke_other, boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&, boost::context::fiber&&) (__f=..., __args#0=...)
at .../8.2.0/include/g++-v8/bits/invoke.h:60
#5 in std::__invoke<boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&>(boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&, boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&) (__fn=..., __args#0=...)
at .../8.2.0/include/g++-v8/bits/invoke.h:96
#6 in std::invoke<boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&>(boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&, boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}&) (__fn=..., __args#0=...)
at .../8.2.0/include/g++-v8/functional:82
#7 in boost::context::detail::fiber_record<boost::context::fiber, boost::context::basic_fixedsize_stack<boost::context::stack_traits>, boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}>::run(void*) (...)
at .../include/boost/context/fiber_fcontext.hpp:144
#8 in boost::context::detail::fiber_entry<boost::context::detail::fiber_record<boost::context::fiber, boost::context::basic_fixedsize_stack<boost::context::stack_traits>, boost::coroutines2::detail::pull_coroutine<int>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}>(boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, make_coro()::{lambda(boost::coroutines2::detail::push_coroutine<int>&)#1}&&)::{lambda(boost::context::fiber&&)#1}> >(boost::context::detail::transfer_t) (t=...)
at .../include/boost/context/fiber_fcontext.hpp:80
#9 in make_fcontext ()
Can we please add something like <asan>on
(similar to <valgrind>on
) which informs AddressSanitizer of the stack changes? It is described here:
google/sanitizers#189 (comment)
https://github.com/llvm-mirror/compiler-rt/blob/master/include/sanitizer/common_interface_defs.h#L166
Compilation fails with an ambiguity between Boost.Context and stdlib tuple apply. For some reason, it works fine if we use std::string
as the coroutine data type, but fails with the ambiguity if we use something like float
. The code also works fine with the compiler set to C++14 or below.
$ cat foo.cpp
#include <boost/coroutine2/all.hpp>
int
main()
{
typedef boost::coroutines2::coroutine<void> coro_t;
coro_t::push_type writer([&](coro_t::pull_type& in){});
return 0;
}
~
$ clang++-7 -std=c++17 foo.cpp -lboost_coroutine -lboost_context
In file included from foo.cpp:1:
In file included from /usr/include/boost/coroutine2/all.hpp:10:
In file included from /usr/include/boost/coroutine2/coroutine.hpp:15:
In file included from /usr/include/boost/coroutine2/detail/coroutine.hpp:37:
In file included from /usr/include/boost/coroutine2/detail/pull_control_block_ecv2.hpp:14:
In file included from /usr/include/boost/context/execution_context.hpp:13:
In file included from /usr/include/boost/context/execution_context_v2.hpp:382:
/usr/include/boost/context/execution_context_v2_void.ipp:58:18: error: call to 'apply' is ambiguous
Ctx cc = apply(
^~~~~
/usr/include/boost/context/execution_context_v2.hpp:70:18: note: in instantiation of member function
'boost::context::detail::record_void<boost::context::execution_context<void>,
boost::context::basic_fixedsize_stack<boost::context::stack_traits>, (lambda at
/usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10)>::run' requested here
t = rec->run( t);
^
/usr/include/boost/context/execution_context_v2_void.ipp:119:56: note: in instantiation of function template specialization 'boost::context::detail::context_entry<boost::context::detail::record_void<boost::context::execution_context<void>,
boost::context::basic_fixedsize_stack<boost::context::stack_traits>, (lambda at
/usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10)> >' requested here
const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
^
/usr/include/boost/context/execution_context_v2_void.ipp:199:24: note: in instantiation of function template specialization 'boost::context::detail::context_create_void<boost::context::execution_context<void>,
boost::context::basic_fixedsize_stack<boost::context::stack_traits>, (lambda at
/usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10)>' requested here
fctx_( detail::context_create_void< execution_context >(
^
/usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:324:5: note: in instantiation of function template specialization
'boost::context::execution_context<void>::execution_context<boost::context::basic_fixedsize_stack<boost::context::stack_traits>,
(lambda at /usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10)>' requested here
ctx{ std::allocator_arg, palloc, salloc,
^/usr/include/boost/coroutine2/detail/create_control_block.ipp:50:22: note: in instantiation of function template specialization
'boost::coroutines2::detail::push_coroutine<void>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>,
(lambda at foo.cpp:7:30)>' requested here
return new ( sp) ControlBlock{ context::preallocated( sp, size, sctx),
(lambda at /usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10)>' requested here
ctx{ std::allocator_arg, palloc, salloc,
^/usr/include/boost/coroutine2/detail/create_control_block.ipp:50:22: note: in instantiation of function template specialization
'boost::coroutines2::detail::push_coroutine<void>::control_block::control_block<boost::context::basic_fixedsize_stack<boost::context::stack_traits>,
(lambda at foo.cpp:7:30)>' requested here
return new ( sp) ControlBlock{ context::preallocated( sp, size, sctx),
^
/usr/include/boost/coroutine2/detail/push_coroutine.ipp:158:10: note: in instantiation of function template specialization
'boost::coroutines2::detail::create_control_block<boost::coroutines2::detail::push_coroutine<void>::control_block,
boost::context::basic_fixedsize_stack<boost::context::stack_traits>, (lambda at foo.cpp:7:30)>' requested here
cb_{ create_control_block< control_block >( salloc, std::forward< Fn >( fn) ) } {
^
/usr/include/boost/coroutine2/detail/push_coroutine.ipp:153:5: note: in instantiation of function template specialization
'boost::coroutines2::detail::push_coroutine<void>::push_coroutine<boost::context::basic_fixedsize_stack<boost::context::stack_traits>,
(lambda at foo.cpp:7:30)>' requested here
push_coroutine{ default_stack(), std::forward< Fn >( fn) } {
^
foo.cpp:7:23: note: in instantiation of function template specialization
'boost::coroutines2::detail::push_coroutine<void>::push_coroutine<(lambda at foo.cpp:7:30), void>' requested here
coro_t::push_type writer([&](coro_t::pull_type& in){});
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8.0.1/../../../../include/c++/8.0.1/tuple:1684:5: note: candidate function [with _Fn = (lambda
at /usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10) &, _Tuple =
std::tuple<boost::context::execution_context<void> &&>]
apply(_Fn&& __f, _Tuple&& __t)
^
/usr/include/boost/context/detail/apply.hpp:39:1: note: candidate function [with Fn = (lambda at
/usr/include/boost/coroutine2/detail/push_control_block_ecv2.ipp:325:10) &, Tpl =
std::tuple<boost::context::execution_context<void> &&>]
apply( Fn && fn, Tpl && tpl)
^
1 error generated.
Consider an I/O bound coroutine as in the example below. This example crashes because Boost.Coroutine2 does not rethrow abi::__forced_unwind
, which was raised by pthread_cancel
.
I have a patch for this problem for coroutines, but some additional support is also needed by the context lib here.
#include <thread>
#include <iostream>
#include <boost/coroutine2/all.hpp>
using coroutine_t = boost::coroutines2::coroutine<int>;
static void io_runner()
{
auto coro = coroutine_t::pull_type([](coroutine_t::push_type &yield) {
do
{
yield(rand());
sleep(1);
} while (1);
});
for (int num : coro)
std::cout << num << std::endl;
}
int main()
{
std::thread io_thread(io_runner);
sleep(10);
pthread_cancel(io_thread.native_handle());
io_thread.join();
return 0;
}
The documentation says that std::begin
and std::end
are overloaded for coroutine<>::pull_type
, but the following example code fails to compile on Clang (Xcode 11.4, macOS 10.15.4):
using namespace boost::coroutines2;
auto my_coro = coroutine<int>::pull_type{
[](coroutine<int>::push_type& yield) {
for (int i = 0; i < 5; ++i) {
yield(i);
}
}
};
for (auto i = std::begin(my_coro); i != std::end(my_coro); ++i) {
// ^ No matching function for call to 'begin', No matching function for call to 'end'
std::cout << *i << std::endl;
}
Calling detail::begin
and detail::end
directly works, and range-based for
also works.
I'm not sure if this is a bug, a documentation problem, or a misunderstanding at my end.
when i create push_type pointer. after doing something, I need to stop this coroutine , i delete this push_type pointer . after this, why this coroutine reenter funtion and resume?
Hello,
I am currently modeling multiple producers using Boost.Coroutine2 and storing them in a container (std::vector). My goal is to leverage OpenMP to accelerate the calls of these coroutines on multiple cores.
However, I am encountering an issue where only one core is running the program. I have been searching for documentation on the combination of OpenMP and Coroutine2 but have not found examples or advice.
Below is a simplified version of my code:
#include <iostream>
#include <boost/coroutine2/all.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#define N 10000000
using namespace boost::coroutines2;
using CoroutinePush = coroutine<void>::push_type;
using CoroutinePull = coroutine<void>::pull_type;
using Funptr = boost::function<void(CoroutinePush&)>;
class Env{
public:
long x=0;
};
void producer(CoroutinePush& yield, Env* env) {
yield(); // init
for (int i = 0; i < N; ++i) {
env->x++; // some work here
yield(); // Yield the produced value
}
}
int main() {
Env* env=new Env();
Funptr producerFunction = boost::bind(&producer, _1, env);
std::vector<CoroutinePull*> l;
for(int i=0;i<N;i++){
l.push_back(new CoroutinePull(producerFunction));
}
#pragma omp parallel for
for(int i=0;i<N;i++){
// #pragma omp critical // if it's uncommented x becomes predictable but 1 thread at a time
{
(*l[i])();
}
}
std::cout << "x:" << env->x << std::endl;
for(int i = 0; i < N; i++) {
delete l[i];
}
delete env;
return 0;
}
My compilation line: g++ -std=c++20 -fopenmp ./g.cpp -lboost_context -lboost_coroutine
I would greatly appreciate any guidance, examples, or advice on how to use Boost.Coroutine2 and OpenMP for multicore execution.
Thank you
Can you, please, give my any ideas on how to resolve the following problem? Thank you, in advance.
I would like to build my program with MinGW compiler and run with Wine, and do it all on Linux.
I reduced my code to the piece, I think, represents the PROBLEM: the resulting executable doesn't catch exceptions, thrown from coroutine and, instead, immediately terminates when running by Wine emulator. Exactly the same executable, being run in native Windows, behaves correctly and catches thrown exceptions as expected. As I would like to run executable with Wine, I need it behave the same way as in native Windows.
My example code is test.cc
:
#include <boost/coroutine2/all.hpp>
#include <stdexcept>
#include <iostream>
using boost::coroutines2::coroutine;
void cooperative(coroutine<void>::push_type &sink)
{
sink();
try
{
throw std::runtime_error("error");
}
catch (const std::runtime_error &e)
{
std::cerr << __LINE__ << ':' << e.what() << '\n';
}
}
int main()
{
coroutine<void>::pull_type source{cooperative};
try
{
source();
}
catch (const std::runtime_error &e)
{
std::cerr << __LINE__ << ':' << e.what() << '\n';
}
}
I build it into executable test.exe
with the script:
#!/bin/sh
BOOST_HOME=~/.conan/data/boost/1.79.0/_/_/package/0dfdb6daf30fb30a61d87d1f67c5e74535fe1679
BOOST_INCLUDE=${BOOST_HOME}/include
BOOST_LIB=${BOOST_HOME}/lib
rm -f test.exe
/usr/bin/x86_64-w64-mingw32-g++-posix \
-m64 \
-std=gnu++2a \
-D_GLIBCXX_USE_CXX11_ABI=1 \
test.cc \
-I${BOOST_INCLUDE} \
-L${BOOST_LIB} \
-lboost_coroutine -lboost_context \
-lws2_32 \
-lwinpthread \
-static -static-libstdc++ -static-libgcc \
-fexceptions \
-o test.exe
WINEPATH= wine ./test.exe
Running with Wine gives me an output:
$ wine ./test.exe
terminate called after throwing an instance of 'std::runtime_error'
abnormal program termination
Running in native Windows gives an output:
> test.exe
16:error
My Linux station has the following software:
$ uname -a
Linux vagrant 5.10.0-14-amd64 #1 SMP Debian 5.10.113-1 (2022-04-29) x86_64 GNU/Linux
$ /usr/bin/x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 10-posix 20210110
$ dpkg -l | grep " g++-mingw-w64 "
ii g++-mingw-w64 10.2.1-6+24.2 all GNU C++ compiler for MinGW-w64
$ wine --version
wine-5.0.3 (Debian 5.0.3-3)
My native windows is Windows 10.
I build Boost lib from https://conan.io/center/boost recipe with MinGW.
I see an important note in the documentation:
Windows using fcontext_t: turn off global program optimization (/GL) and change /EHsc (compiler
assumes that functions declared as extern "C" never throw a C++ exception) to /EHs (tells compiler
assumes that functions declared as extern "C" may throw an exception).
and think it may be related to the problem I met. If so, can you, please, document the solution for MinGW compiler besides MSVC.
Here is the test program: https://gist.github.com/ztlpn/77a0ff1c0537f5ce8f81227c511b028b
I expect that the exception will be rethrown and the program will print Exception: Error
, but it prints nothing. If the yield()
statement is uncommented, everything is as expected.
I am testing with coroutine2 library from boost 1.64.0.
We tried to build and run coroutine2 test for Boost with VS2017 Update 5 on Windows. It failed to build due to the error C2039: 'forced_unwind': is not a member of 'boost::context::detail'. Could you please help take a look at this? Thank you!
Reproduce steps:
Expected result:
All tests passed
Actual result:
Whole log file please see attachment.
log_x86_test_coroutine2.log
.\boost/coroutine2/detail/pull_control_block_cc.ipp(85): error C2039: 'forced_unwind': is not a member of 'boost::context::detail'
.\boost/context/detail/invoke.hpp(24): note: see declaration of 'boost::context::detail'
.\boost/coroutine2/detail/create_control_block.ipp(51): note: see reference to function template instantiation 'boost::coroutines2::detail::pull_coroutine::control_block::control_block<_Ty,void(__cdecl &)(boost::coroutines2::detail::push_coroutine &)>(boost::context::preallocated,StackAllocator &&,Fn)' being compiled
with
[
T=int,
_Ty=boost::coroutines2::default_stack,
StackAllocator=boost::coroutines2::default_stack,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
.\boost/coroutine2/detail/create_control_block.ipp(50): note: see reference to function template instantiation 'boost::coroutines2::detail::pull_coroutine::control_block::control_block<_Ty,void(__cdecl &)(boost::coroutines2::detail::push_coroutine &)>(boost::context::preallocated,StackAllocator &&,Fn)' being compiled
with
[
T=int,
_Ty=boost::coroutines2::default_stack,
StackAllocator=boost::coroutines2::default_stack,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
.\boost/coroutine2/detail/pull_coroutine.ipp(54): note: see reference to function template instantiation 'ControlBlock *boost::coroutines2::detail::create_control_block<boost::coroutines2::detail::pull_coroutine::control_block,_Ty,void(__cdecl &)(boost::coroutines2::detail::push_coroutine &)>(StackAllocator &&,Fn)' being compiled
with
[
ControlBlock=boost::coroutines2::detail::pull_coroutine::control_block,
T=int,
_Ty=boost::coroutines2::default_stack,
StackAllocator=boost::coroutines2::default_stack,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
.\boost/coroutine2/detail/pull_coroutine.ipp(48): note: see reference to function template instantiation 'boost::coroutines2::detail::pull_coroutine::pull_coroutine<boost::coroutines2::default_stack,void(__cdecl &)(boost::coroutines2::detail::push_coroutine &)>(StackAllocator &&,Fn)' being compiled
with
[
T=int,
StackAllocator=boost::coroutines2::default_stack,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
.\boost/coroutine2/detail/pull_coroutine.ipp(48): note: see reference to function template instantiation 'boost::coroutines2::detail::pull_coroutine::pull_coroutine<boost::coroutines2::default_stack,void(__cdecl &)(boost::coroutines2::detail::push_coroutine &)>(StackAllocator &&,Fn)' being compiled
with
[
T=int,
StackAllocator=boost::coroutines2::default_stack,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
libs\coroutine2\test\test_coroutine.cpp(237): note: see reference to function template instantiation 'boost::coroutines2::detail::pull_coroutine::pull_coroutine<void(__cdecl &)(boost::coroutines2::detail::push_coroutine &),void>(Fn)' being compiled
with
[
T=int,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
libs\coroutine2\test\test_coroutine.cpp(237): note: see reference to function template instantiation 'boost::coroutines2::detail::pull_coroutine::pull_coroutine<void(__cdecl &)(boost::coroutines2::detail::push_coroutine &),void>(Fn)' being compiled
with
[
T=int,
Fn=void (__cdecl &)(boost::coroutines2::detail::push_coroutine &)
]
Continuing the boost-users thread, to avoid spamming the list too much now this is identified as a bug. (And possibly a continuation of #4 )
As suggested I tried using current develop (boostorg/context@b4e18ff6) of Boost.Context (header and lib); it made no difference.
After also updating Boost.Coroutine2 to current develop (6bfa86e), the error changed:
/mnt/ThirdParty/boost/boost_1_63_0/include/boost/coroutine2/detail/push_control_block_cc.ipp:332:44: error: call of overloaded 'callcc(const std::allocator_arg_t&, boost::context::preallocated&, boost::context::basic_fixedsize_stack<boost::context::stack_traits>&, boost::coroutines2::detail::wrapper<boost::coroutines2::detail::push_coroutine<void>::control_block::control_block(boost::context::preallocated, StackAllocator, Fn&&) [with StackAllocator = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = {anonymous}::TestMethod(void*)::__lambda14]::__lambda7, {anonymous}::TestMethod(void*)::__lambda14>)' is ambiguous
std::forward< Fn >( fn) ) );
^
/mnt/ThirdParty/boost/boost_1_63_0/include/boost/coroutine2/detail/push_control_block_cc.ipp:332:44: note: candidates are:
/mnt/ThirdParty/boost/boost_1_63_0/include/boost/context/continuation.hpp:474:1: note: boost::context::continuation boost::context::callcc(std::allocator_arg_t, StackAlloc, Fn&&, Arg ...) [with StackAlloc = boost::context::preallocated; Fn = boost::context::basic_fixedsize_stack<boost::context::stack_traits>&; Arg = {boost::coroutines2::detail::wrapper<boost::coroutines2::detail::push_coroutine<void>::control_block::control_block(boost::context::preallocated, StackAllocator, Fn&&) [with StackAllocator = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = {anonymous}::TestMethod(void*)::__lambda14]::__lambda7, {anonymous}::TestMethod(void*)::__lambda14>}]
callcc( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Arg ... arg) {
^
/mnt/ThirdParty/boost/boost_1_63_0/include/boost/context/continuation.hpp:488:1: note: boost::context::continuation boost::context::callcc(std::allocator_arg_t, boost::context::preallocated, StackAlloc, Fn&&, Arg ...) [with StackAlloc = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = boost::coroutines2::detail::wrapper<boost::coroutines2::detail::push_coroutine<void>::control_block::control_block(boost::context::preallocated, StackAllocator, Fn&&) [with StackAllocator = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = {anonymous}::TestMethod(void*)::__lambda14]::__lambda7, {anonymous}::TestMethod(void*)::__lambda14>; Arg = {}]
callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Arg ... arg) {
^
/mnt/ThirdParty/boost/boost_1_63_0/include/boost/context/continuation.hpp:519:1: note: boost::context::continuation boost::context::callcc(std::allocator_arg_t, boost::context::preallocated, StackAlloc, Fn&&) [with StackAlloc = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = boost::coroutines2::detail::wrapper<boost::coroutines2::detail::push_coroutine<void>::control_block::control_block(boost::context::preallocated, StackAllocator, Fn&&) [with StackAllocator = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = {anonymous}::TestMethod(void*)::__lambda14]::__lambda7, {anonymous}::TestMethod(void*)::__lambda14>]
callcc( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn) {
^
/mnt/ThirdParty/boost/boost_1_63_0/include/boost/context/continuation.hpp:462:1: note: boost::context::continuation boost::context::callcc(Fn&&, Arg ...) [with Fn = const std::allocator_arg_t&; Arg = {boost::context::preallocated, boost::context::basic_fixedsize_stack<boost::context::stack_traits>, boost::coroutines2::detail::wrapper<boost::coroutines2::detail::push_coroutine<void>::control_block::control_block(boost::context::preallocated, StackAllocator, Fn&&) [with StackAllocator = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = {anonymous}::TestMethod(void*)::__lambda14]::__lambda7, {anonymous}::TestMethod(void*)::__lambda14>}; <template-parameter-1-3> = void]
callcc( Fn && fn, Arg ... arg) {
^
like, force the coroutine function to raise a forced_unwind
? or do I have to implement cancellation points manually?
In the environment disabled of exception, the errors are occured like below:
error: cannot use 'try/throw' with exceptions disabled
Hi,
The documentation states that,
Calling coroutine<>::push_type::operator() and coroutine<>::pull_type::operator() from inside the same coroutine results in undefined behaviour.
and provides the following example,
boost::coroutines2::coroutine<void>::push_type coro(
[&](boost::coroutines2::coroutine<void>::pull_type& yield){
yield();
});
coro();
Shouldn't this be something like this?
boost::coroutines2::coroutine<void>::push_type coro(
[&](boost::coroutines2::coroutine<void>::pull_type& yield){
coro();
});
coro();
I have the following small example of generating ints in https://gist.github.com/ipapadop/08722cf2033f018a273a1d7114164da7
In Boost.Coroutine, pull_type (line 68) accepts std::bind, whereas with Boost.Coroutine2 (Boost 1.62) I'm getting an error:
/usr/local/boost-1.62/include/boost/context/execution_context_v2.hpp:141:23: error: no matching function for call to ‘apply(std::remove_reference<std::_Bind<boost::coroutines2::detail::pull_coroutine<T>::control_block::control_block(boost::context::preallocated, StackAllocator, Fn&&) [with StackAllocator = boost::context::basic_fixedsize_stack<boost::context::stack_traits>; Fn = std::_Bind<void (*(std::_Placeholder<1>, unsigned int, unsigned int, int))(boost::coroutines2::detail::push_coroutine<int>&, unsigned int, int, int)>; T = int]::<lambda(std::decay<std::_Bind<void (*(std::_Placeholder<1>, unsigned int, unsigned int, int))(boost::coroutines2::detail::push_coroutine<int>&, unsigned int, int, int)> >::type&, boost::context::execution_context<int*>, int*)>(std::_Bind<void (*(std::_Placeholder<1>, unsigned int, unsigned int, int))(boost::coroutines2::detail::push_coroutine<int>&, unsigned int, int, int)>, std::_Placeholder<1>, std::_Placeholder<2>)>&>::type, std::remove_reference<std::tuple<boost::context::execution_context<int*>&&, int*>&>::type)’
Is there any reason why they are not part of Couroutine2?
Similar to this question from coroutines, I have run into issues with ASAN. I looked into this previous issue and was wondering if there is any update on this.
I get a stack underflow when a running coroutine is deconstructed. According to the issue with coroutines, this is caused by a detail::forced_unwind exception
that is caught but I have been able to create it without catching the exception:
auto p = pull_type([&](push_type &s) {
while (true) sink();
});
This results in the following ASAN error:
==48790==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x00010cc4acc0 at pc 0x000108aaaedf bp 0x00010cc4a7d0 sp 0x00010cc49f90
WRITE of size 168 at 0x00010cc4acc0 thread T0
#0 0x108aaaede in wrap_memmove (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x1aede)
0x00010cc4acc0 is located 128192 bytes inside of 131072-byte region [0x00010cc2b800,0x00010cc4b800)
allocated by thread T0 here:
#0 0x108ad5abd in wrap_malloc (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x45abd)
#1 0x107cb9b3e in boost::context::basic_fixedsize_stack<boost::context::stack_traits>::allocate() fixedsize_stack.hpp:57
#2 0x107cb9535 in boost::coroutines2::detail::pull_coroutine<void>::control_block* boost::coroutines2::detail::create_control_block<boost::coroutines2::detail::pull_coroutine<void>::control_block, boost::context::basic_fixedsize_stack<boost::context::stack_traits>, terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)>(boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)&&) create_control_block.ipp:32
#3 0x107cb92bd in boost::coroutines2::detail::pull_coroutine<void>::pull_coroutine<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)>(boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)&&) pull_coroutine.ipp:184
#4 0x107cb9214 in boost::coroutines2::detail::pull_coroutine<void>::pull_coroutine<boost::context::basic_fixedsize_stack<boost::context::stack_traits>, terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)>(boost::context::basic_fixedsize_stack<boost::context::stack_traits>&&, terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)&&) pull_coroutine.ipp:184
#5 0x107cb9099 in boost::coroutines2::detail::pull_coroutine<void>::pull_coroutine<terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&), void>(terrier::common::PoolContext::in_::'lambda'(boost::coroutines2::detail::push_coroutine<void>&)&&) pull_coroutine.ipp:179
Is there a workaround to resolve this ASAN issue?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.