Is std::future<void> viable according to the standard? - c++

libstdc++ apparently has a specialization for std::future of void type. I'm asking how viable this solution is, as the following doesn't seem to work on gcc:
Demo
#include <future>
#include <cstdio>
int main()
{
try {
std::packaged_task<void()> fn([]{ printf("Hello World!\n"); });
std::future<void> fut = fn.get_future();
fn();
fut.wait();
printf("Future was set!\n");
} catch(const std::exception& e) {
printf("%s\n", e.what());
}
}
It throws an unknown system error... (Unknown error -1) What is it, is it me or the implementation?
My idea was to wait for a std::future<void> to indicate that the function has run on a another task where I'm shipping the packaged task to.

Related

std::promise::set_exception with type non extending std::exception calls terminate

In the following snippet
#include <iostream>
#include <future>
int main()
{
auto ep = std::make_exception_ptr( X ); // (1)
std::promise<int> p;
p.set_exception(ep);
try {
p.get_future().get(); // (2)
} catch(const std::exception& exc) {
std::cout << exc.what();
}
return 0;
}
if X in line (1) is a type not extending std::exception, the call at line (2) will call terminate. I can't find anywhere this specification.
Godbolt with latest gcc and msvc
As noted in comments, the problem is not catching the right type of exception, e.g. using catch(...).

Why is gcc not catching an exception from a multi target function?

I'm using the target attribute to generate different function implementations depending on the CPU architecture. If one of the functions throws an exception it doesn't get caught if I compile with gcc, but with clang it works as expected.
If there is only a single implementation of the function it does work for gcc as well.
Is this a bug in gcc?
Example (godbolt):
#include <stdexcept>
#include <iostream>
using namespace std;
__attribute__((target("default")))
void f() {
throw 1;
}
__attribute__((target("sse4.2,bmi")))
void f() {
throw 2;
}
int main()
{
try {
f();
}
catch(... )
{
std::cout << "Caught exception" << std::endl;
}
}
Output of gcc:
terminate called after throwing an instance of 'int'
Output of clang:
Caught exception
I reported this and a GCC developer confirmed it as a bug: link
For now a workaround seems to wrap the function and use the gnu::noipa attribute to disable interprocedural optimizations:
__attribute__((target("default")))
void f() {
throw 1;
}
__attribute__((target("sse4.2")))
void f() {
throw 2;
}
[[gnu::noipa]]
void f1()
{
f();
}
int main()
{
try {
f1();
}
catch(... )
{
return 0;
}
return 1;
}
The bug is now fixed in gcc's master branch and should be released with gcc version 13.

How can i return an error to std::filesystem?

For example, this is how I do it using runtime_error
#include <exception>
#include <filesystem>
std::exception &foo(){
try {
if(!std::filesystem::is_directory(std::filesystem::path("sdfsdf"))){
throw std::runtime_error("Error14");
}
}
catch (std::exception &e) {
return e;
}
}
int main(){
foo().what();
// then i do smth with this error
}
how to do something similar, but with errors returning from std :: filesystem, I mean
std::filesystem::filesystem_error
I have tried this->
#include <filesystem>
std::filesystem::filesystem_error &foo()
{
try {
if(!std::filesystem::is_directory(std::filesystem::path("sdfsdf"))){
throw std::filesystem::filesystem_error("ERROR14", std::error_code());
}
}
catch (std::filesystem::filesystem_error &e) {
// if (e.code == success)
{
return e;
}
}
}
int main()
{
foo();
}
How to return such 'e' if there is no exception(i mean throw)
CppReference documents the constructors for std::filesystem::filesystem_error.
Just use one of them:
throw std::filesystem::filesystem_error("Error14", std::error_code());
You'll probably want to put in a better message and error code :-)
std::filesystem::is_directory has a few overloads. If you provide an std::error_code object as the last argument it will not throw, but instead set the value of the error code object if an operating system error occurs. So you could use this overload to set the std::error_code object and create the std::filesystem::filesystem_error from it:
std::filesystem::filesystem_error foo()
{
std::error_code err{};
if (!std::filesystem::is_directory(std::filesystem::path("sdfsdf"), err))
{
return std::filesystem::filesystem_error{ "ERROR14", err };
}
return std::filesystem::filesystem_error{ "SUCCESS", err };
}
Note that this is returning by value; if you return by reference it will be a reference to a local variable that is destroyed after the function returns, and use of such a dangling reference would lead to undefined behaviour.

Error using boost::asio::deadline_timer while execution

I am trying to implement a basic deadline timer using this code:
class Example
{
Example(boost::asio::io_service& ios, config& cfg)
: ios_(ios), cfg_(cfg), tcp_client_(ios) {
state = new State();
boost::asio::deadline_timer t(ios, boost::posix_time::seconds(5));
t.async_wait(boost::bind(&bse_dummy_exchange::start_heartbeats,this,boost::asio::placeholders::error,boost::ref(t)));
}
~Example() = default;
void start_heartbeats(const boost::system::error_code& e,boost::asio::deadline_timer& t)
{
std::cout << "Hello, world!\n";
t.expires_from_now(boost::posix_time::seconds(5));
t.async_wait(boost::bind(&bse_dummy_exchange::start_heartbeats,this,boost::asio::placeholders::error,boost::ref(t)));
}
}
Compilation goes fine, but while executing I get this error message which I don't understand, can someone please help me with it:
Hello, world!
bse_dummy_exchange: ../nptl/pthread_mutex_lock.c:425:
__pthread_mutex_lock_full: Assertion `INTERNAL_SYSCALL_ERRNO (e, __err)
!= ESRCH || !robust' failed.
Aborted (core dumped)
You don't show the mutex - so we can't answer.
That said, about everything is going wrong with respect to async that can go wrong:
you have a memory leak (state is an owned pointer member, but you defaulted the destructor? https://www.google.com/search?q=cppreference+rule+of+three&oq=cppreference+rule+of+three&aqs=chrome..69i57j69i64.2928j0j7&sourceid=chrome&ie=UTF-8)
This is UB:
boost::asio::deadline_timer t(ios, boost::posix_time::seconds(5));
t.async_wait(boost::bind(&bse_dummy_exchange::start_heartbeats,this,boost::asio::placeholders::error,boost::ref(t)));
async_ return immediately, but the operation runs ... well ... asynchronously. In your case t is a local variable that immediately goes out of scope after the constructor returns. So, that's not gonna work.
exactly the same problem in start_heartbeats
(I'm for the sake of understanding your code assuming that Example was actually named use_dummy_exchange)
At the very least, the timer needs to have lifetime extending beyond the lifetime of the async_wait.
Minimal Fixed Version
Of course, not fixing anything related to the mutex error - that was not included:
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
struct config { };
struct TcpClient {
TcpClient(boost::asio::io_service& ios) : ios_(ios){}
private:
boost::asio::io_service& ios_;
};
struct Example {
struct State {};
std::unique_ptr<State> state;
Example(boost::asio::io_service& ios, config& cfg)
: state(std::unique_ptr<State>()),
ios_(ios),
cfg_(cfg),
tcp_client_(ios)
{
heartbeats();
}
void heartbeats(const boost::system::error_code& e = {}) {
std::cout << "Hello, world!" << std::endl;
if (!e) {
t.expires_from_now(boost::posix_time::seconds(5));
t.async_wait([this](auto ec) { heartbeats(ec); });
}
}
private:
boost::asio::io_service& ios_;
config cfg_;
TcpClient tcp_client_;
boost::asio::deadline_timer t{ios_};
};
int main() {
boost::asio::io_service ios;
config cfg;
Example ex(ios, cfg);
ios.run_for(std::chrono::seconds(12));
}
Prints
Hello, world!
Hello, world!
Hello, world!
It has no memory leak, and runs clean under UBSan/ASan

Use Boost strand in conjunction with std::future

I have come across a use case where I would like to use a Boost strand in conjunction with a std::future.
To reduce code duplication, I have written a generic function which will post a task to a boost strand and return the future.
// Some definitions first...
typedef boost::asio::io_service::strand cb_strand;
typedef std::shared_ptr< cb_strand > cb_strand_ptr;
The code looks something like:
//////////////////////////////////////////////////////////////////////////
template <class Task>
auto post_future_to_strand(cb_strand_ptr apStrand, Task task)
{
using return_type = decltype(task());
auto promise = std::make_shared<std::promise<return_type>>();
auto future = promise->get_future();
apStrand->wrap
(
[promise, task]()
{
try
{
promise->set_value(task());
}
catch (...)
{
// LOG ERROR ...
// NOTE: Exceptions can be thrown when setting the exception!
try
{
promise->set_exception(std::current_exception());
}
catch (...)
{
//LOG ERROR ...
}
}
}
);
return future;
};
I then hoped to post a future to a strand as presented in the following example:
std::future<int> f = post_future_to_strand(m_apStrand, std::bind(&foo::bar, this))
std::cout << "foo::bar() -> int is " << f.get() << std::endl;
Unfortunately, I get a runtime exception:
terminate called after throwing an instance of 'std::future_error'
what(): std::future_error: Broken promise
Signal: SIGABRT (Aborted)
Having read the docs, I think I understand what a broken promise is and how the situation arises; however, I feel like I am capturing the promise in the lambda so all should be well. I am a newcomer to this world of lambdas, so perhaps my understanding is amiss.
Ubuntu Zesty
GCC 6.3 (configured for C++14 with cmake)
You wrap the task, but you never post it. Therefore, the wrapped task is immediately destructed, and with that the promise.
There's another pitfall, things only work if you run the io_service on a different thread than the one blocking for the future... Otherwise you have created a deadlock:
Live On Coliru deadlock
Now that you have multiple threads, you need to avoid the race-condition where the service exits before the task is posted in the first place.
Bonus:
I'd suggest a far simpler take on the wrapper:
template <typename Task>
auto post_future_to_strand(cb_strand_ptr apStrand, Task task)
{
auto package = std::make_shared<std::packaged_task<decltype(task())()> >(task);
auto future = package->get_future();
apStrand->post([package] { (*package)(); });
return future;
}
Full Demo
Live On Coliru
#include <boost/asio.hpp>
#include <future>
#include <iostream>
using cb_strand_ptr = boost::asio::strand*;
//////////////////////////////////////////////////////////////////////////
template <typename Task>
auto post_future_to_strand(cb_strand_ptr apStrand, Task task)
{
auto package = std::make_shared<std::packaged_task<decltype(task())()> >(task);
auto future = package->get_future();
apStrand->post([package] { (*package)(); });
return future;
}
struct Foo {
boost::asio::strand s;
cb_strand_ptr m_apStrand = &s;
Foo(boost::asio::io_service& svc) : s{svc} {}
void do_it() {
std::future<int> f = post_future_to_strand(m_apStrand, std::bind(&Foo::bar, this));
std::cout << "foo::bar() -> int is " << f.get() << std::endl;
}
int bar() {
return 42;
}
};
int main() {
boost::asio::io_service svc;
auto lock = std::make_unique<boost::asio::io_service::work>(svc); // prevent premature exit
std::thread th([&]{ svc.run(); });
Foo foo(svc);
foo.do_it();
lock.reset(); // allow service to exit
th.join();
}
Prints
foo::bar() -> int is 42