c++ - Correctly using atomic<T> -
i struggling writing lockless code atomic variables c++11 thread pool class based on https://github.com/nbsdx/threadpool. here modified class:
class threadpool { public: explicit threadpool(int threadcount) : _jobsleft(0), _bailout(false) { _threads = std::vector<std::thread>(threadcount); (int index = 0; index < threadcount; ++index) { _threads[index] = std::move(std::thread([this] { this->task(); })); } } void addjob(std::function<void(void)> job) { { std::lock_guard<std::mutex> lock(_queuemutex); _queue.emplace(job); } { std::lock_guard<std::mutex> lock(_jobsleftmutex); ++_jobsleft; } _jobavailablevar.notify_one(); } void joinall() { if (!_bailout) { _bailout = true; _jobavailablevar.notify_all(); (auto& x : _threads) { if (x.joinable()) { x.join(); } } } } void waitall() { std::unique_lock<std::mutex> lock(_jobsleftmutex); if (_jobsleft > 0) { _waitvar.wait(lock, [this] { return _jobsleft == 0; }); } } private: void task() { while (!_bailout) { std::function<void(void)> job; { std::unique_lock<std::mutex> lock(_queuemutex); _jobavailablevar.wait(lock, [this] { return _queue.size() > 0 || _bailout; }); if (_bailout) { return; } job = _queue.front(); _queue.pop(); } job(); { std::lock_guard<std::mutex> lock(_jobsleftmutex); --_jobsleft; } _waitvar.notify_one(); } } std::vector<std::thread> _threads; std::queue<std::function<void(void)>> _queue; int _jobsleft; std::atomic<bool> _bailout; std::condition_variable _jobavailablevar; std::condition_variable _waitvar; std::mutex _jobsleftmutex; std::mutex _queuemutex; };
i puzzled following , appreciate pointers:
- how make usage of
_bailout
atomic? played aroundatomic_flag
not work in scenario. - is possible make
_jobsleft
behave correctly usingatomic<int>
without locks? had issue original thread poolwaitall()
not correctly return in rare cases. works fine feel wastes performance.
edit: final version normal locks available here: https://github.com/stfx/threadpool2
look @ atomic methods: http://en.cppreference.com/w/cpp/atomic/atomic
you should use load method atomically read value. however, aware following not atomic.
if (!_bailout) { _bailout = true;
there method perform these comparison , value swaps. see compare_exchange_weak method. jobcount can use atomic. ++ , -- atomic.
however, aware atomic single method call, after call situation may change. still need synchronized queue , need lock. not need standard os lock, can create lock using atomic variable (using store , compare_exchange_weak methods). see following post: https://webkit.org/blog/6161/locking-in-webkit/
Comments
Post a Comment