reject tasks in jobber dtor

This commit is contained in:
2018-12-12 22:36:22 +07:00
parent be72e90532
commit 86449be43a
2 changed files with 49 additions and 11 deletions

View File

@@ -17,7 +17,8 @@
#include <memory>
#include <vector>
#include <utility>
#include <algorithm>
#include <exception>
#include <stdexcept>
#include <type_traits>
#include <condition_variable>
@@ -41,6 +42,12 @@ namespace jobber_hpp
timeout
};
class jobber_cancelled_exception : public std::runtime_error {
public:
jobber_cancelled_exception()
: std::runtime_error("jobber has stopped working") {}
};
class jobber final : private detail::noncopyable {
public:
explicit jobber(std::size_t threads);
@@ -106,6 +113,7 @@ namespace jobber_hpp
public:
virtual ~task() noexcept = default;
virtual void run() noexcept = 0;
virtual void cancel() noexcept = 0;
};
template < typename R, typename F, typename... Args >
@@ -117,7 +125,8 @@ namespace jobber_hpp
template < typename U >
concrete_task(U&& u, std::tuple<Args...>&& args);
void run() noexcept final;
promise<R> promise() noexcept;
void cancel() noexcept final;
promise<R> future() noexcept;
};
template < typename F, typename... Args >
@@ -129,7 +138,8 @@ namespace jobber_hpp
template < typename U >
concrete_task(U&& u, std::tuple<Args...>&& args);
void run() noexcept final;
promise<void> promise() noexcept;
void cancel() noexcept final;
promise<void> future() noexcept;
};
}
@@ -137,7 +147,7 @@ namespace jobber_hpp
{
inline jobber::jobber(std::size_t threads) {
try {
threads_.resize(std::max<std::size_t>(1u, threads));
threads_.resize(threads);
for ( std::thread& thread : threads_ ) {
thread = std::thread(&jobber::worker_main_, this);
}
@@ -168,10 +178,10 @@ namespace jobber_hpp
std::unique_ptr<task_t> task = std::make_unique<task_t>(
std::forward<F>(f),
std::make_tuple(std::forward<Args>(args)...));
promise<R> promise = task->promise();
promise<R> future = task->future();
std::lock_guard<std::mutex> guard(tasks_mutex_);
push_task_(priority, std::move(task));
return promise;
return future;
}
inline void jobber::pause() noexcept {
@@ -283,6 +293,13 @@ namespace jobber_hpp
inline void jobber::shutdown_() noexcept {
{
std::lock_guard<std::mutex> guard(tasks_mutex_);
while ( !tasks_.empty() ) {
task_ptr task = pop_task_();
if ( task ) {
task->cancel();
--active_task_count_;
}
}
cancelled_.store(true);
cond_var_.notify_all();
}
@@ -341,7 +358,12 @@ namespace jobber_hpp
}
template < typename R, typename F, typename... Args >
promise<R> jobber::concrete_task<R, F, Args...>::promise() noexcept {
void jobber::concrete_task<R, F, Args...>::cancel() noexcept {
promise_.reject(jobber_cancelled_exception());
}
template < typename R, typename F, typename... Args >
promise<R> jobber::concrete_task<R, F, Args...>::future() noexcept {
return promise_;
}
@@ -366,7 +388,12 @@ namespace jobber_hpp
}
template < typename F, typename... Args >
promise<void> jobber::concrete_task<void, F, Args...>::promise() noexcept {
void jobber::concrete_task<void, F, Args...>::cancel() noexcept {
promise_.reject(jobber_cancelled_exception());
}
template < typename F, typename... Args >
promise<void> jobber::concrete_task<void, F, Args...>::future() noexcept {
return promise_;
}
}

View File

@@ -7,12 +7,12 @@
#define CATCH_CONFIG_FAST_COMPILE
#include "catch.hpp"
#include <cmath>
#include <numeric>
#include <cstring>
#include "jobber.hpp"
#include "promise.hpp"
namespace jb = jobber_hpp;
namespace pr = promise_hpp;
@@ -989,6 +989,16 @@ TEST_CASE("jobber") {
});
REQUIRE_THROWS_AS(pv0.get(), std::exception);
}
{
auto pv0 = pr::promise<int>();
{
jb::jobber j{0};
pv0 = j.async([](){
return 42;
});
}
REQUIRE_THROWS_AS(pv0.get(), jb::jobber_cancelled_exception);
}
{
int v5 = 5;
@@ -1015,13 +1025,14 @@ TEST_CASE("jobber") {
REQUIRE(v5 == 4);
}
{
const float pi = 3.14159265358979323846264338327950288f;
jb::jobber j(1);
auto p0 = j.async([](float angle){
return std::sin(angle);
}, M_PI);
}, pi);
auto p1 = j.async([](float angle){
return std::cos(angle);
}, M_PI * 2);
}, pi * 2);
REQUIRE(p0.get() == Approx(0.f).margin(0.01f));
REQUIRE(p1.get() == Approx(1.f).margin(0.01f));
}