threadpool: guard against exceptions in jobs, and armour plating

Those would, if uncaught, exit run and leave the waiter to wait
indefinitely for the number of active jobs to reach 0
This commit is contained in:
moneromooo-monero 2020-08-12 22:13:29 +00:00
parent 5d850dde99
commit 6a37da837e
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
8 changed files with 72 additions and 60 deletions

View file

@ -521,14 +521,14 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
// send all requests in parallel
std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false);
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
tools::threadpool::waiter waiter(tpool);
for (size_t n = 0; n < dns_urls.size(); ++n)
{
tpool.submit(&waiter,[n, dns_urls, &records, &avail, &valid](){
records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]);
});
}
waiter.wait(&tpool);
waiter.wait();
size_t cur_index = first_index;
do

View file

@ -120,7 +120,7 @@ threadpool::waiter::~waiter()
catch (...) { /* ignore */ }
try
{
wait(NULL);
wait();
}
catch (const std::exception &e)
{
@ -128,12 +128,12 @@ threadpool::waiter::~waiter()
}
}
void threadpool::waiter::wait(threadpool *tpool) {
if (tpool)
tpool->run(true);
bool threadpool::waiter::wait() {
pool.run(true);
boost::unique_lock<boost::mutex> lock(mt);
while(num)
cv.wait(lock);
return !error();
}
void threadpool::waiter::inc() {
@ -166,7 +166,8 @@ void threadpool::run(bool flush) {
lock.unlock();
++depth;
is_leaf = e.leaf;
e.f();
try { e.f(); }
catch (const std::exception &ex) { e.wo->set_error(); try { MERROR("Exception in threadpool job: " << ex.what()); } catch (...) {} }
--depth;
is_leaf = false;

View file

@ -55,12 +55,16 @@ public:
class waiter {
boost::mutex mt;
boost::condition_variable cv;
threadpool &pool;
int num;
bool error_flag;
public:
void inc();
void dec();
void wait(threadpool *tpool); //! Wait for a set of tasks to finish.
waiter() : num(0){}
bool wait(); //! Wait for a set of tasks to finish, returns false iff any error
void set_error() noexcept { error_flag = true; }
bool error() const noexcept { return error_flag; }
waiter(threadpool &pool) : pool(pool), num(0), error_flag(false) {}
~waiter();
};