Skip to content

Instantly share code, notes, and snippets.

@dmikis
Last active November 5, 2020 12:19
Show Gist options
  • Save dmikis/032e2d5a32e9df86ef7bd6512a4897a5 to your computer and use it in GitHub Desktop.
Save dmikis/032e2d5a32e9df86ef7bd6512a4897a5 to your computer and use it in GitHub Desktop.
Snippet from rays for a review
using FnVector = std::vector<std::function<void()>>;
usign FnWorkBroker = WorkBroker<FnVector::iterator>;
void worker(FnWorkBroker* broker)
{
for (const auto& fn : *broker) {
fn();
}
}
int main() {
FnVector fns = /* ... */;
FnWorkBroker broker(fns.begin(), fns.end());
std::vector<std::thread> ts(std::thread::hardware_concurrency());
for (size_t i = 0; i < ts.size(); ++i) {
ts[i] = std::thread(worker, &broker);
}
broker.wait([](float progress) {
std::cout << '\r' << static_cast<int>(100 * progress) << '%'
<< std::flush;
});
for (auto& t : ts) {
t.join();
}
return 0;
}
#pragma once
#include <chrono>
#include <condition_variable>
namespace gfx::util {
template <typename It>
class WorkBroker {
class WorkItemItertor {
public:
using difference_type =
typename std::iterator_traits<It>::difference_type;
using value_type = typename std::iterator_traits<It>::value_type;
using point = typename std::iterator_traits<It>::pointer;
using reference = typename std::iterator_traits<It>::reference;
using iterator_category = std::forward_iterator_tag;
WorkItemItertor(It it, WorkBroker* broker)
: _it(it)
, _broker(broker)
{
}
WorkItemItertor(const WorkItemItertor&) = default;
WorkItemItertor& operator=(const WorkItemItertor&) = default;
bool operator==(const WorkItemItertor& other) const
{
return _it == other._it;
}
bool operator!=(const WorkItemItertor& other) const
{
return !(*this == other);
}
typename std::iterator_traits<It>::reference operator*()
{
return *_it;
}
WorkItemItertor& operator++()
{
_it = _broker->nextIt();
return *this;
}
WorkItemItertor operator++(int)
{
auto copy = *this;
++*this;
return copy;
}
private:
It _it;
WorkBroker* _broker;
};
public:
WorkBroker(It begin, It end)
: _begin(begin)
, _it(begin)
, _end(end)
{
}
WorkBroker(const WorkBroker& other)
: _begin(other._begin)
, _it(other._it)
, _end(other._end)
{
}
void wait()
{
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [&]() { return _it == _end; });
}
void wait(std::function<void(float)> reportProgress)
{
std::unique_lock<std::mutex> lock(_mutex);
using namespace std::chrono_literals;
while (!_cv.wait_for(lock, 1s, [&]() { return _it == _end; })) {
const auto total = std::distance(_begin, _end);
reportProgress(
static_cast<float>(total - std::distance(_it, _end))
/ static_cast<float>(total));
}
}
WorkItemItertor begin() { return WorkItemItertor(_it, this); }
WorkItemItertor end() { return WorkItemItertor(_end, this); }
private:
const It _begin;
It _it, _end;
mutable std::mutex _mutex;
mutable std::condition_variable _cv;
It nextIt()
{
It next = _end;
{
std::lock_guard<std::mutex> lock(_mutex);
if (_it != _end) {
next = ++_it;
}
}
_cv.notify_one();
return next;
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment