mirror of
https://github.com/KjellKod/g3log.git
synced 2025-04-17 07:13:28 +02:00
Input from Gem Chen triggerd review of shared_queue (now made clearer) and active.hpp (now all header file)
This commit is contained in:
parent
74963e13f1
commit
2e5d323b52
@ -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;
|
|
||||||
}
|
|
@ -11,7 +11,7 @@
|
|||||||
* and inspired from Herb Sutter's C++11 Active Object
|
* 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
|
* 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
|
* e-mail: hedstrom at kjellkod dot cc
|
||||||
* linkedin: http://linkedin.com/se/kjellkod */
|
* linkedin: http://linkedin.com/se/kjellkod */
|
||||||
|
|
||||||
@ -28,21 +28,39 @@ typedef std::function<void() > Callback;
|
|||||||
|
|
||||||
class Active {
|
class Active {
|
||||||
private:
|
private:
|
||||||
Active(); // Construction ONLY through factory createActive();
|
Active() : done_(false) {} // Construction ONLY through factory createActive();
|
||||||
void run();
|
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_;
|
shared_queue<Callback> mq_;
|
||||||
std::thread thd_;
|
std::thread thd_;
|
||||||
bool done_; // finished flag : set by ~Active
|
bool done_;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Active();
|
virtual ~Active() {
|
||||||
void send(Callback msg_);
|
send([this] { done_ = true;});
|
||||||
static std::unique_ptr<Active> createActive();
|
thd_.join();
|
||||||
|
}
|
||||||
|
|
||||||
Active(const Active&) = delete;
|
void send(Callback msg_) { mq_.push(msg_); }
|
||||||
Active& operator=(const Active&) = delete;
|
|
||||||
|
/// 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
|
} // kjellkod
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
* This exampel was totally inspired by Anthony Williams lock-based data structures in
|
* This exampel was totally inspired by Anthony Williams lock-based data structures in
|
||||||
* Ref: "C++ Concurrency In Action" http://www.manning.com/williams */
|
* Ref: "C++ Concurrency In Action" http://www.manning.com/williams */
|
||||||
|
|
||||||
#ifndef SHARED_QUEUE
|
#pragma once
|
||||||
#define SHARED_QUEUE
|
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -29,15 +28,15 @@ class shared_queue
|
|||||||
mutable std::mutex m_;
|
mutable std::mutex m_;
|
||||||
std::condition_variable data_cond_;
|
std::condition_variable data_cond_;
|
||||||
|
|
||||||
shared_queue& operator=(const shared_queue&); // c++11 feature not yet in vs2010 = delete;
|
shared_queue& operator=(const shared_queue&) = delete;
|
||||||
shared_queue(const shared_queue& other); // c++11 feature not yet in vs2010 = delete;
|
shared_queue(const shared_queue& other) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shared_queue(){}
|
shared_queue(){}
|
||||||
|
|
||||||
void push(T item){
|
void push(T item){
|
||||||
std::lock_guard<std::mutex> lock(m_);
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
queue_.push(item);
|
queue_.push(std::move(item));
|
||||||
data_cond_.notify_one();
|
data_cond_.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +53,12 @@ public:
|
|||||||
|
|
||||||
/// Try to retrieve, if no items, wait till an item is available and try again
|
/// Try to retrieve, if no items, wait till an item is available and try again
|
||||||
void wait_and_pop(T& popped_item){
|
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())
|
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());
|
popped_item=std::move(queue_.front());
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
@ -73,5 +74,3 @@ public:
|
|||||||
return queue_.size();
|
return queue_.size();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user