Skip to content

Instantly share code, notes, and snippets.

@arturl
Last active December 21, 2015 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arturl/6360774 to your computer and use it in GitHub Desktop.
Save arturl/6360774 to your computer and use it in GitHub Desktop.
using namespace std;
class exception_list : public exception
{
public:
typedef exception_ptr value_type;
typedef const value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef vector<exception_ptr>::iterator iterator;
typedef vector<exception_ptr>::const_iterator const_iterator;
exception_list() {}
exception_list(const vector<exception_ptr>& exceptions) : exceptions_(exceptions) {}
size_t size() const {
return exceptions_.size();
}
const_iterator begin() const {
return exceptions_.begin();
}
const_iterator end() const {
return exceptions_.end();
}
private:
vector<exception_ptr> exceptions_;
};
class task_group
{
private:
enum class exception_handling_mode{ handle, ignore };
enum class dummy_type { tag };
// scratch buffer for locally allocated tasks
static const auto scratch_buffer_size = 128;
char buff[scratch_buffer_size];
char* buffptr = &buff[0];
task_group(exception_handling_mode mode, dummy_type) : exception_handling_mode_(mode)
{
}
template<class Func>
task_group(const Func& f, dummy_type) : exception_handling_mode_(exception_handling_mode::handle), exception_handler_func_(f)
{
}
public:
static const auto ignore_exceptions = exception_handling_mode::ignore;
template<class ExceptionHandler>
task_group(ExceptionHandler&& handler) : task_group(handler, dummy_type::tag) {}
template<class Func>
void run(const Func& f)
{
auto size = sizeof(concurrency::task_handle<Func>);
concurrency::task_handle<Func> *th;
if (buffptr + size >= buff + scratch_buffer_size)
{
th = new concurrency::task_handle<Func>(f);
owned_tasks.push_back(th);
}
else
{
// dtor is empty, so no need to call it
// TODO: ensure proper alignment
th = new(buffptr)concurrency::task_handle<Func>(f);
buffptr += size;
}
stg_.run(*th);
}
// wait swallows exceptions now
void wait() /* noexcept */
{
try
{
// PPL wait throws
stg_.wait();
}
catch (...)
{
}
}
~task_group()
{
stg_.wait();
try
{
stg_.wait();
}
catch (...)
{
if (exception_handling_mode_ == exception_handling_mode::handle)
{
auto exp = std::current_exception();
vector<exception_ptr> exceptions = { exp }; // TBD, for now, only one exception (PPL limitation)
exception_handler_func_(exceptions);
}
}
for (auto task : owned_tasks)
{
delete task;
}
}
private:
function<void(exception_list)> exception_handler_func_;
concurrency::structured_task_group stg_;
exception_handling_mode exception_handling_mode_; // this member can be avoided by checking if exception_handler_func_ is set
vector<concurrency::details::_UnrealizedChore*> owned_tasks; // this can be avoided, but requires changes in the PPL
};
#if 0
template<typename Func>
auto make_future(task_group &tg, Func&& func) -> std::future<decltype(func())>
{
typedef decltype(func()) T;
auto p = std::make_unique<std::promise<T>>();
auto f = p->get_future();
tg.run([func, p{ std::move(p) }] {
p->set_value(func());
});
return f;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment