The std::future_error code() doesn't match its what() - c++

Following Kerrek's guide in What is std::promise?. I try similar sample codes but it doesn't achieve what I expect.
That is, the caught future_errc error's member function code() doesn't match its what(). Exactly speaking, the call code() returns correctly and what() returns the information of next bit of code(). I doubt that this is something wrong in Visual Studio 2012.
Sample codes:
std::future<int> test_future_error1()
{
std::promise<int> prom;
std::future<int> fu = prom.get_future();
prom.set_value(5566);
return fu;
}
//---------------------------------------------------------------
std::future<int> test_future_error2()
{
std::promise<int> prom;
std::future<int> fu = prom.get_future();
std::future<int> fu2 = prom.get_future(); // throw std::future_errc::future_already_retrieved
prom.set_value(5566);
return fu;
}
//---------------------------------------------------------------
std::future<int> test_future_error3()
{
std::promise<int> prom;
std::future<int> fu = prom.get_future();
prom.set_value(5566);
prom.set_value(7788); // throw std::future_errc::promise_already_satisfied
return fu;
}
//---------------------------------------------------------------
std::future<int> test_future_error4()
{
std::promise<int> prom;
std::future<int> fu = prom.get_future();
return fu;
} // throw std::future_errc::broken_promise at fu.get()
//---------------------------------------------------------------
std::future<int> test_future_error5()
{
std::future<int> fu;
return fu;
} // throw std::future_errc::no_state at fu.get()
//---------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
try {
std::future<int> fu = test_future_error3();
int a = fu.get();
std::cout << "a= " << a << std::endl;
} catch(const std::future_error &e) {
std::cout << "future_error:" << std::endl;
if( e.code() == std::future_errc::broken_promise )
std::cout << "code() == std::future_errc::broken_promise" << std::endl;
else if( e.code() == std::future_errc::future_already_retrieved )
std::cout << "code() == std::future_errc::future_already_retrieved" << std::endl;
else if( e.code() == std::future_errc::promise_already_satisfied )
std::cout << "code() == std::future_errc::promise_already_satisfied" << std::endl;
else if( e.code() == std::future_errc::no_state )
std::cout << "code() == std::future_errc::no_state" << std::endl;
else
std::cout << "code() == unknown" << std::endl;
std::cout << "what() == " << e.what() << std::endl;
} catch(const std::exception &e) {
std::cout << "excepton: " << e.what() << std::endl;
}
std::system("pause");
return 0;
}
Result:
future_error:
code() == std::future_errc::promise_already_satisfied
what() == no state

Related

How do I make async_read_some of asio to call a callback?

I'm trying to use serial_port of asio(standlone) to get data from a device. But I can't read even a byte.
I post a screenshoot of the example usage found from documentation website as below :
enter image description here
enter image description here
https://think-async.com/Asio/asio-1.24.0/doc/asio/reference/basic_serial_port/async_read_some.html
There are 3 question I have:
What is the specific type of the first parameter of async_read_some? std::vector<uint8_t>, for example?
How to bind a class member function as the callback/handler?
Is it right that we just make sure io_context.run() run on a background thread and call async_read_some just once?
I'll appreciate it if you guys could help me check out my code or give some advice.
class NmeaSource {
public:
explicit NmeaSource(std::shared_ptr<asio::io_context> io, const nlohmann::json& settings);
void parse();
void handle(const asio::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes read.
);
private:
void open();
std::string m_port;
int m_baudrate;
std::shared_ptr<asio::io_context> m_io;
std::shared_ptr<asio::serial_port> m_serial;
unsigned char m_readBuffer[1024];
};
NmeaSource::NmeaSource(std::shared_ptr<asio::io_context> io, const nlohmann::json& settings)
:m_io(io)
{
try {
setPort(settings.at("port"));
setBaudrate(settings.at("baudrate"));
//LOG("");
std::cout << "port: " << m_port << ", baudrate: " << m_baudrate << std::endl;
}
catch (nlohmann::json::basic_json::type_error& e1) {
std::cout << "type is wrong " << e1.what() << std::endl;
throw e1;
}
catch (nlohmann::json::basic_json::out_of_range& e2) {
std::cout << "key is not found " << e2.what() << std::endl;
throw e2;
}
catch (...)
{
std::cout << "unknown error"<< std::endl;
exit(-1);
}
open();
}
void NmeaSource::open()
{
m_serial = std::make_shared<asio::serial_port>(*m_io);
asio::error_code ec;
m_serial->open(m_port, ec);
if (!ec) {
asio::serial_port_base::baud_rate baudrate(m_baudrate);
m_serial->set_option(baudrate);
std::cout << "successfully" << std::endl;
}
else {
std::cout << "failed " << ec.message() <<std::endl;
}
}
void NmeaSource::handle(const asio::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes read.
)
{
if (!error) {
std::cout << bytes_transferred << " bytes read!" << std::endl;
}
else {
std::cout << error.message() << std::endl;
}
}
void NmeaSource::parse()
{
m_serial->async_read_some(
asio::buffer(m_readBuffer, 1024),
std::bind(&NmeaSource::handle, this,
std::placeholders::_1,
std::placeholders::_2)
);
}
int main()
{
auto io = std::make_shared<asio::io_context>();
//std::thread t(std::bind(static_cast<size_t(asio::io_service::*)()>(&asio::io_service::run), io.get()));
std::thread t([&io]() {io->run(); });
NmeaSource rtk(io, nlohmann::json{ {"port", "COM3"}, {"baudrate", 115200} });
rtk.parse();
for (;;)
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
The output

How to catch exceptions from multiple tasks in Casablanca

I'm trying to join two pplx tasks using the && operator of task, where both sub tasks can throw exceptions.
I understand from the ppl documentation that I can catch an exception in a final, task-based continuation. This works in Casablanca as well.
However, I can catch only one exception in my final continuation. If both sub tasks throw, one remains unhandled.
Here's a minimal example illustrating my problem:
#include <pplx/pplxtasks.h>
#include <iostream>
int main(int argc, char *argv[])
{
int a = 0; int b = 0;
auto t1 = pplx::create_task([a] { return a+1; })
.then([](int a) { throw std::runtime_error("a");
return a+1; });
auto t2 = pplx::create_task([b] { return b+1; })
.then([](int b) { throw std::runtime_error("b");
return b+1; });
(t1 && t2)
.then([] (std::vector<int>) { /*...*/ })
.then([] (pplx::task<void> prev) {
try {
prev.get();
} catch (std::runtime_error e) {
std::cout << "caught " << e.what() << std::endl;
}
});
std::cin.get();
}
The try/catch is able to catch whichever of the two exceptions occurs first. How can I catch the other?
You would have to add a final task-based continuation to each sub-task.
I would suggest re-throwing any exception you catch, however, that would likely be a bad idea since the continuation task doesn't realize that the 2 exceptions are equivalent see below example for proof.
Output:
caught a
caught final a
caught b
Also, if you remove the sleep, you will receive a "Trace/breakpoint trap" exception.
#include <pplx/pplxtasks.h>
#include <iostream>
int main(int argc, char *argv[])
{
int a = 0; int b = 2;
auto t1 = pplx::create_task([a] { return a+1; })
.then([](int a) { throw std::runtime_error("a"); return a+1; })
.then([] (pplx::task<int> prev)
{
int retVal = -1;
try
{
retVal = prev.get();
}
catch (std::runtime_error e)
{
std::cout << "caught " << e.what() << std::endl;
throw e;
}
return retVal;
});
auto t2 = pplx::create_task([b] { return b+1; })
.then([](int b) { throw std::runtime_error("b"); return b+1; })
.then([] (pplx::task<int> prev)
{
int retVal = -1;
try
{
sleep(1);
retVal = prev.get();
}
catch (std::runtime_error e)
{
std::cout << "caught " << e.what() << std::endl;
throw e;
}
return retVal;
});
(t1 && t2)
.then([] (std::vector<int> v) { for(int i : v) { std::cout << i << std::endl; } })
.then([] (pplx::task<void> prev)
{
try
{
prev.get();
}
catch (std::runtime_error e)
{
std::cout << "caught final " << e.what() << std::endl;
}
}).get();
}

Boost.Asio socket is being blocked

The for loop in main.cpp, which calls a function that uses boost::mutex and that reads from a socket using read_until, only runs once, after that it's like it's blocked. I've tried putting a continue before the closing brackets and then it crashes. It's probably related to threading.
// MAIN.CPP
int main(int argc, char* argv[])
{
std::cout << "Enter port number: ";
std::string port;
std::getline(std::cin, port);
int tempPort = std::stoi(port);
Network * network = new Network(tempPort);
int it = 0;
boost::thread * t1;
t1 = new boost::thread([&network, &it]
{
while (true)
{
boost::asio::ip::tcp::socket * sock = new boost::asio::ip::tcp::socket(network->io_service);
network->accept(*sock);
if (network->socketList.size() > 0)
{
for (boost::asio::ip::tcp::socket * s : network->socketList)
{
if (s->remote_endpoint().address().to_string() == sock->remote_endpoint().address().to_string())
{
continue;
}
else {
network->socketList.push_back(sock);
std::cout << s->remote_endpoint().address().to_string() << " connected." << std::endl;
}
}
}
else {
network->socketList.push_back(sock);
std::cout << sock->remote_endpoint().address().to_string() << " connected." << std::endl;
}
}
});
while (true)
{
for (boost::asio::ip::tcp::socket * sock : network->socketList)
{
std::cout << "on range-based for loop" << std::endl;
network->readChatMessage(*(sock));
}
}
t1->join();
return 0;
}
// NETWORK.CPP
int Network::sendChatMessage(boost::asio::ip::tcp::socket & socket, ChatMessage & message)
{
try
{
boost::system::error_code err;
boost::asio::streambuf buf;
{
std::ostream out(&buf);
boost::archive::text_oarchive oa(out);
oa & message;
std::cout << std::string(message.text.begin(), message.text.end()) << std::endl;
}
m.lock();
write(socket, buf, err);
if (err)
{
std::cout << err.message() << std::endl;
}
m.unlock();
std::cout << "Mensagem enviada com sucesso!" << std::endl;
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
int Network::readChatMessage(boost::asio::ip::tcp::socket & socket)
{
std::cout << "in readChatMessage()" << std::endl;
boost::system::error_code err;
boost::asio::streambuf buf;
m.lock();
boost::asio::read_until(socket, buf, '\0', err);
if (err)
{
std::cout << err.message() << std::endl;
}
m.unlock();
std::istream in(&buf);
ChatMessage message;
boost::archive::text_iarchive ia(in);
ia & message;
std::cout << std::string(message.text.begin(), message.text.end()) << std::endl;
this->sendChatMessage(socket, message);
return 0;
}
I was able to fix the problem after debugging and editing the code a bit, then I was able to see there was an error happening: input stream error due to the serialization Input/Output. I handled the error properly, unlocking the mutex when the error happened and not letting the mutex go undone.
Snippet:
int Network::readChatMessage(boost::asio::ip::tcp::socket & socket)
{
std::cout << "in readChatMessage()" << std::endl;
boost::system::error_code err;
boost::asio::streambuf buf;
m.lock();
boost::asio::read_until(socket, buf, '\0', err);
if (err)
{
m.unlock();
std::cout << err.message() << std::endl;
return 0;
}
else {
m.unlock();
std::istream in(&buf);
ChatMessage message;
boost::archive::text_iarchive ia(in);
ia & message;
std::cout << std::string(message.text.begin(), message.text.end()) << std::endl;
this->sendChatMessage(socket, message);
return 0;
}
m.unlock();
return 0;
}

Cascade Poco Exception

I try to cascade exception in Poco.
void debug() {
try {
...
xmlFile.parseDocument(*_sim);
...
}
} catch (Poco::Exception& error) {
std::cout << "I'm here" << endl;
std::cout << "Error : " << error.displayText() << std::endl;
}
}
void XMLParser::parseDocument(Manager &manager) {
...
try {
Poco::XML::NodeList* policyList = root->childNodes();
for (uint node=0; node < policyList->length(); node++)
if (policyList->item(node)->hasChildNodes())
manager.insertRule(parseRule(node, policyList->item(node)));
} catch(Poco::Exception& error) {
std::cout << "Error : " << error.displayText() << std::endl;
error.rethrow();
}
}
Rule* XMLParser::parseRule(int flowID, Poco::XML::Node* rule) throw() {
....
if (tLink._srcPort < 0)
throw new Poco::Exception("Source Port isn't valid");
....
}
The deepest exception are thrown, but it does not continue to outer functions.
The program is terminated. Why?
You throw a Poco::Exception pointer so you can not catch it by reference.
Remove 'new'. This should work:
....
if (tLink._srcPort < 0)
throw Poco::Exception("Source Port isn't valid");
....

Berkeley DB, concurrent queues

I'm trying to implement a concurrent persistent queue using Berkeley DB. As a starter I tried to make two process which both appends to the DB:
#include <unistd.h>
#include <sstream>
#include <db_cxx.h>
class Queue : public DbEnv
{
public:
Queue ( ) :
DbEnv(0),
db(0)
{
set_flags(DB_CDB_ALLDB, 1);
open("/tmp/db", DB_INIT_LOCK |
DB_INIT_LOG |
DB_INIT_TXN |
DB_INIT_MPOOL |
DB_RECOVER |
DB_CREATE |
DB_THREAD,
0);
db = new Db(this, 0);
db->set_flags(DB_RENUMBER);
db->open(NULL, "db", NULL, DB_RECNO, DB_CREATE | DB_AUTO_COMMIT | DB_THREAD, 0);
}
virtual ~Queue ()
{
db->close(0);
delete db;
close(0);
}
protected:
Db * db;
};
class Enqueue : public Queue
{
public:
Enqueue ( ) : Queue() { }
virtual ~Enqueue () { }
bool push(const std::string& s)
{
int res;
DbTxn * txn;
try {
txn_begin(NULL, &txn, DB_TXN_SYNC | DB_TXN_WAIT );
db_recno_t k0[4]; // not sure how mutch data is needs???
k0[0] = 0;
Dbt val((void*)s.c_str(), s.length());
Dbt key((void*)&k0, sizeof(k0[0]));
key.set_ulen(sizeof(k0));
key.set_flags(DB_DBT_USERMEM);
res = db->put(txn, &key, &val, DB_APPEND);
if( res == 0 ) {
txn->commit(0);
return true;
} else {
std::cerr << "push failed: " << res << std::endl;
txn->abort();
return false;
}
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
txn->abort();
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
txn->abort();
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
txn->abort();
return false;
}
}
};
using namespace std;
int main(int argc, const char *argv[])
{
fork();
Enqueue e;
stringstream ss;
for(int i = 0; i < 10; i++){
ss.str("");
ss << "asdf" << i;
cout << ss.str() << endl;
if( ! e.push(ss.str()) )
break;
}
return 0;
}
Compiling it:
g++ test.cxx -I/usr/include/db4.8 -ldb_cxx-4.8
Create the db-dir
mkdir /tmp/db
And when I run it I get all kind of errors (segmentations fault, allocation error, and some times it actually works)
I'm sure that I have missed some locking, but I just do not know how to do it. So, any hints and/or suggestions to fix this are most welcome.
Just for the record, here is the solution I have settled on after much googleing and trial'n'error.
The application is a call home process, where the producer is adding data, and consumer tries to send it home. If the consumer fails to send it home, it must try again. The database must not block for producer while the consumer is trying to sink data.
The code has a file lock, and will only allow one consumer process.
Here are the code:
#include <db_cxx.h>
#include <sstream>
#include <fstream>
#include <vector>
#include <boost/interprocess/sync/file_lock.hpp>
class Queue : public DbEnv
{
public:
Queue ( bool sync ) :
DbEnv(0),
db(0)
{
set_flags(DB_CDB_ALLDB, 1);
if( sync )
set_flags(DB_TXN_NOSYNC, 0);
else
set_flags(DB_TXN_NOSYNC, 1);
open("/tmp/db", DB_INIT_LOCK |
DB_INIT_LOG | DB_INIT_TXN | DB_INIT_MPOOL |
DB_REGISTER | DB_RECOVER | DB_CREATE | DB_THREAD,
0);
db = new Db(this, 0);
db->set_flags(DB_RENUMBER);
db->open(NULL, "db", NULL, DB_RECNO, DB_CREATE | DB_AUTO_COMMIT | DB_THREAD, 0);
}
virtual ~Queue ()
{
db->close(0);
delete db;
close(0);
}
protected:
Db * db;
};
struct Transaction
{
Transaction() : t(0) { }
bool init(DbEnv * dbenv ){
try {
dbenv->txn_begin(NULL, &t, 0);
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
return false;
}
return true;
}
~Transaction(){ if( t!=0) t->abort(); }
void abort() { t->abort(); t = 0; }
void commit() { t->commit(0); t = 0; }
DbTxn * t;
};
struct Cursor
{
Cursor() : c(0) { }
bool init( Db * db, DbTxn * t) {
try {
db->cursor(t, &c, 0);
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
return false;
}
return true;
}
~Cursor(){ if( c!=0) c->close(); }
void close(){ c->close(); c = 0; }
Dbc * c;
};
class Enqueue : public Queue
{
public:
Enqueue ( bool sync ) : Queue(sync) { }
virtual ~Enqueue () { }
bool push(const std::string& s)
{
int res;
Transaction transaction;
if( ! transaction.init(this) )
return false;
try {
db_recno_t k0[4]; // not sure how mutch data is needs???
k0[0] = 0;
Dbt val((void*)s.c_str(), s.length());
Dbt key((void*)&k0, sizeof(k0[0]));
key.set_ulen(sizeof(k0));
key.set_flags(DB_DBT_USERMEM);
res = db->put(transaction.t, &key, &val, DB_APPEND);
if( res == 0 ) {
transaction.commit();
return true;
} else {
std::cerr << "push failed: " << res << std::endl;
return false;
}
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
return false;
}
}
};
const char * create_file(const char * f ){
std::ofstream _f;
_f.open(f, std::ios::out);
_f.close();
return f;
}
class Dequeue : public Queue
{
public:
Dequeue ( bool sync ) :
Queue(sync),
lock(create_file("/tmp/db-test-pop.lock")),
number_of_records_(0)
{
std::cout << "Trying to get exclusize access to database" << std::endl;
lock.lock();
}
virtual ~Dequeue ()
{
}
bool pop(size_t number_of_records, std::vector<std::string>& records)
{
if( number_of_records_ != 0 ) // TODO, warning
abort();
Cursor cursor;
records.clear();
if( number_of_records_ != 0 )
abort(); // TODO, warning
// Get a cursor
try {
db->cursor(0, &cursor.c, 0);
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
abort();
return false;
}
// Read and delete
try {
Dbt val;
db_recno_t k0 = 0;
Dbt key((void*)&k0, sizeof(k0));
for( size_t i = 0; i < number_of_records; i ++ ) {
int get_res = cursor.c->get(&key, &val, DB_NEXT);
if( get_res == 0 )
records.push_back(std::string((char *)val.get_data(), val.get_size()));
else
break;
}
number_of_records_ = records.size();
if( number_of_records_ == 0 ) {
abort();
return false;
} else {
return true;
}
} catch( DbException e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
abort();
return false;
} catch( std::exception e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
abort();
return false;
}
}
bool commit()
{
if( number_of_records_ == 0 )
return true;
Transaction transaction;
Cursor cursor;
if( ! transaction.init(this) )
return false;
if( ! cursor.init(db, transaction.t) )
return false;
// Read and delete
try {
Dbt val;
db_recno_t k0 = 0;
Dbt key((void*)&k0, sizeof(k0));
for( size_t i = 0; i < number_of_records_; i ++ ) {
int get_res = cursor.c->get(&key, &val, DB_NEXT);
if( get_res == 0 )
cursor.c->del(0);
else
break; // this is bad!
}
number_of_records_ = 0;
cursor.close();
transaction.commit();
return true;
} catch( DbException e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
return false;
}
}
void abort()
{
number_of_records_ = 0;
}
private:
boost::interprocess::file_lock lock;
size_t number_of_records_;
sigset_t orig_mask;
};
Please let me know if you see any errors, or if know about an easier way to do this.