Input from Gem Chen triggerd review of shared_queue (now made clearer) and active.hpp (now all header file)

This commit is contained in:
KjellKod 2013-12-19 23:47:31 -07:00
parent 74963e13f1
commit 2e5d323b52
3 changed files with 36 additions and 73 deletions

View File

@ -1,54 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Example of a Active Object, using C++11 std::thread mechanisms to make it
* safe for thread communication.
*
* This was originally published at http://sites.google.com/site/kjellhedstrom2/active-object-with-cpp0x
* and inspired from Herb Sutter's C++11 Active Object
* http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads
*
* Last update 2013-09-25 by Kjell Hedstrom,
* e-mail: hedstrom at kjellkod dot cc
* linkedin: http://linkedin.com/se/kjellkod */
#include "active.hpp"
using namespace kjellkod;
Active::Active() : done_(false) {
}
Active::~Active() {
send([this] {
done_ = true;
});
thd_.join();
}
/// Add asynchronously a work-message to queue
void Active::send(Callback msg_) {
mq_.push(msg_);
}
/// Will wait for msgs if queue is empty
/// A great explanation of how this is done (using Qt's library):
/// http://doc.qt.nokia.com/stable/qwaitcondition.html
void Active::run() {
while (!done_) {
// wait till job is available, then retrieve it and
// executes the retrieved job in this thread (background)
Callback func;
mq_.wait_and_pop(func);
func();
}
}
/// Factory: safe construction of object before thread start
std::unique_ptr<Active> Active::createActive() {
std::unique_ptr<Active> aPtr(new Active());
aPtr->thd_ = std::thread(&Active::run, aPtr.get());
return aPtr;
}

View File

@ -11,7 +11,7 @@
* and inspired from Herb Sutter's C++11 Active Object
* http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads
*
* Last update 2013-09-25 by Kjell Hedstrom,
* Last update 2013-12-19 by Kjell Hedstrom,
* e-mail: hedstrom at kjellkod dot cc
* linkedin: http://linkedin.com/se/kjellkod */
@ -28,21 +28,39 @@ typedef std::function<void() > Callback;
class Active {
private:
Active(); // Construction ONLY through factory createActive();
void run();
Active() : done_(false) {} // Construction ONLY through factory createActive();
Active(const Active&) = delete;
Active& operator=(const Active&) = delete;
void run() {
while (!done_) {
Callback func;
mq_.wait_and_pop(func);
func();
}
}
shared_queue<Callback> mq_;
std::thread thd_;
bool done_; // finished flag : set by ~Active
bool done_;
public:
virtual ~Active();
void send(Callback msg_);
static std::unique_ptr<Active> createActive();
virtual ~Active() {
send([this] { done_ = true;});
thd_.join();
}
Active(const Active&) = delete;
Active& operator=(const Active&) = delete;
void send(Callback msg_) { mq_.push(msg_); }
/// Factory: safe construction of object before thread start
static std::unique_ptr<Active> createActive() {
std::unique_ptr<Active> aPtr(new Active());
aPtr->thd_ = std::thread(&Active::run, aPtr.get());
return aPtr;
}
};
} // kjellkod

View File

@ -12,8 +12,7 @@
* This exampel was totally inspired by Anthony Williams lock-based data structures in
* Ref: "C++ Concurrency In Action" http://www.manning.com/williams */
#ifndef SHARED_QUEUE
#define SHARED_QUEUE
#pragma once
#include <queue>
#include <mutex>
@ -29,15 +28,15 @@ class shared_queue
mutable std::mutex m_;
std::condition_variable data_cond_;
shared_queue& operator=(const shared_queue&); // c++11 feature not yet in vs2010 = delete;
shared_queue(const shared_queue& other); // c++11 feature not yet in vs2010 = delete;
shared_queue& operator=(const shared_queue&) = delete;
shared_queue(const shared_queue& other) = delete;
public:
shared_queue(){}
void push(T item){
std::lock_guard<std::mutex> lock(m_);
queue_.push(item);
queue_.push(std::move(item));
data_cond_.notify_one();
}
@ -54,10 +53,12 @@ public:
/// Try to retrieve, if no items, wait till an item is available and try again
void wait_and_pop(T& popped_item){
std::unique_lock<std::mutex> lock(m_); // note: unique_lock is needed for std::condition_variable::wait
std::unique_lock<std::mutex> lock(m_);
while(queue_.empty())
{ // The 'while' loop below is equal to
data_cond_.wait(lock); //data_cond_.wait(lock, [](bool result){return !queue_.empty();});
{
data_cond_.wait(lock);
// This 'while' loop is equal to
// data_cond_.wait(lock, [](bool result){return !queue_.empty();});
}
popped_item=std::move(queue_.front());
queue_.pop();
@ -73,5 +74,3 @@ public:
return queue_.size();
}
};
#endif