Last active
November 5, 2020 12:19
-
-
Save dmikis/032e2d5a32e9df86ef7bd6512a4897a5 to your computer and use it in GitHub Desktop.
Snippet from rays for a review
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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