C++11 同步队列、注册回调函数、生产者消费者代码记录
同步队列:
template <typename T>
class SynchronizedQueue {
public:
SynchronizedQueue()
: queue_()
, mutex_()
, cond_()
, request_to_end_(false)
, enqueue_data_(true)
{
}
void enqueue(const T& data)
{
std::unique_lock<std::mutex> lock(mutex_);
if (enqueue_data_)
{
queue_.push(data);
cond_.notify_one();
}
}
bool dequeue(T& result)
{
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.empty() && (!request_to_end_))
{
cond_.wait(lock);
}
if (request_to_end_)
{
doEndActions();
return false;
}
result = queue_.front();
queue_.pop();
return true;
}
void stopQueue()
{
std::unique_lock<std::mutex> lock(mutex_);
request_to_end_ = true;
cond_.notify_one();
}
unsigned int size()
{
std::unique_lock<std::mutex> lock(mutex_);
return static_cast<unsigned int>(queue_.size());
}
bool isEmpty() const
{
std::unique_lock<std::mutex> lock(mutex_);
return (queue_.empty());
}
private:
void doEndActions()
{
enqueue_data_ = false;
while (!queue_.empty())
{
queue_.pop();
}
}
std::queue<T> queue_;
mutable std::mutex mutex_;
std::condition_variable cond_;
bool request_to_end_;
bool enqueue_data_;
};
Task基类:
class BaseTask {
public:
using PrintFunc = std::function<void(int level, std::string& msg)>;
BaseTask() = default;
virtual ~BaseTask() = default;
virtual void Start() {}
virtual void Stop() {}
virtual void RegisterPrint(PrintFunc cb) {
print_ = cb;
}
protected:
volatile bool stop_flag_ = false;
std::shared_ptr<std::thread> worker_ = nullptr;
virtual void Process(std::string name) {}
virtual void Print(int level, std::string msg) {
if (this->print_)
this->print_(0, msg);
}
PrintFunc print_ = nullptr;
};
Task派生类,生产者
template <typename T>
class Producer :public BaseTask {
public:
using DataCallBack = std::function<void(T&)>;
Producer() {}
virtual ~Producer() override { this->Stop(); }
Producer(const Producer & r) = default;
Producer &operator=(const Producer &r) = default;
virtual void Start() override {
if (worker_)
return;
else {
worker_.reset(new std::thread(std::bind(&Producer::Process, this, std::string("Producer thread"))));
}
}
virtual void Stop() override {
if (!worker_)
return;
stop_flag_ = true;
worker_->join();
worker_.reset();
stop_flag_ = false;
}
void RegisterDataCallback(DataCallBack cb) { cb_ = cb; }
protected:
virtual void Process(std::string name) override {
int i = 0;
while (!stop_flag_) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
T data = i++;
if (cb_) cb_(data);
const int buffer_len = 128;
time_t t = time(0);
struct tm* now = localtime(&t);
char buffer[buffer_len];
strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
}
}
private:
DataCallBack cb_ = nullptr;
};
Task派生类,消费者
template <typename T>
class Consumer:public BaseTask {
public:
Consumer(): datas_(new SynchronizedQueue<T>), producer_(new Producer<T>){}
virtual ~Consumer() override { this->Stop(); }
Consumer(const Consumer & r) = default;
Consumer &operator=(const Consumer &r) = default;
virtual void Start() override {
if (worker_)
return;
else {
producer_->RegisterDataCallback(std::bind(&Consumer::DataCallback, this, std::placeholders::_1));
producer_->Start();
worker_.reset(new std::thread(std::bind(&Consumer::Process, this, std::string("Worker thread"))));
}
}
virtual void Stop() override {
if (!worker_)
return;
producer_->Stop();
stop_flag_ = true;
worker_->join();
worker_.reset();
stop_flag_ = false;
}
virtual void RegisterPrint(PrintFunc cb) override {
print_ = cb;
this->producer_->RegisterPrint(cb);
}
protected:
virtual void Process(std::string name) override {
while (!stop_flag_) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
T data;
this->datas_->dequeue(data);
const int buffer_len = 128;
time_t t = time(0);
struct tm* now = localtime(&t);
char buffer[buffer_len];
strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
}
}
void DataCallback(T& data) {
if (datas_)
datas_->enqueue(data);
}
private:
std::shared_ptr<SynchronizedQueue<T>> datas_ = nullptr;
std::shared_ptr<Producer<T> > producer_ = nullptr;
volatile bool stop_flag_ = false;
};
测试函数
int main(int argc, char** argv)
{
Notify notify;
Consumer<int> consumer_;
consumer_.RegisterPrint(std::bind(&Notify::Print, ¬ify, std::placeholders::_1, std::placeholders::_2));
consumer_.Start();
while (1) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
全部代码
#include <memory>
#include <iostream>
#include <thread>
#include <queue>
#include <string>
#include <mutex>
#include <functional>
#include <condition_variable>
class Notify {
public:
Notify() {}
~Notify() {}
Notify(const Notify & r) = default;
Notify &operator=(const Notify &rhs) = default;
void Print(int level, std::string& msg) {
switch (level) {
case 0:
std::cout << msg << std::endl;
break;
case 1:
default:
std::cerr << msg << std::endl;
}
}
};
template <typename T>
class SynchronizedQueue {
public:
SynchronizedQueue()
: queue_()
, mutex_()
, cond_()
, request_to_end_(false)
, enqueue_data_(true)
{
}
void enqueue(const T& data)
{
std::unique_lock<std::mutex> lock(mutex_);
if (enqueue_data_)
{
queue_.push(data);
cond_.notify_one();
}
}
bool dequeue(T& result)
{
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.empty() && (!request_to_end_))
{
cond_.wait(lock);
}
if (request_to_end_)
{
doEndActions();
return false;
}
result = queue_.front();
queue_.pop();
return true;
}
void stopQueue()
{
std::unique_lock<std::mutex> lock(mutex_);
request_to_end_ = true;
cond_.notify_one();
}
unsigned int size()
{
std::unique_lock<std::mutex> lock(mutex_);
return static_cast<unsigned int>(queue_.size());
}
bool isEmpty() const
{
std::unique_lock<std::mutex> lock(mutex_);
return (queue_.empty());
}
private:
void doEndActions()
{
enqueue_data_ = false;
while (!queue_.empty())
{
queue_.pop();
}
}
std::queue<T> queue_;
mutable std::mutex mutex_;
std::condition_variable cond_;
bool request_to_end_;
bool enqueue_data_;
};
class BaseTask {
public:
using PrintFunc = std::function<void(int level, std::string& msg)>;
BaseTask() = default;
virtual ~BaseTask() = default;
virtual void Start() {}
virtual void Stop() {}
virtual void RegisterPrint(PrintFunc cb) {
print_ = cb;
}
protected:
volatile bool stop_flag_ = false;
std::shared_ptr<std::thread> worker_ = nullptr;
virtual void Process(std::string name) {}
virtual void Print(int level, std::string msg) {
if (this->print_)
this->print_(0, msg);
}
PrintFunc print_ = nullptr;
};
template <typename T>
class Producer :public BaseTask {
public:
using DataCallBack = std::function<void(T&)>;
Producer() {}
virtual ~Producer() override { this->Stop(); }
Producer(const Producer & r) = default;
Producer &operator=(const Producer &r) = default;
virtual void Start() override {
if (worker_)
return;
else {
worker_.reset(new std::thread(std::bind(&Producer::Process, this, std::string("Producer thread"))));
}
}
virtual void Stop() override {
if (!worker_)
return;
stop_flag_ = true;
worker_->join();
worker_.reset();
stop_flag_ = false;
}
void RegisterDataCallback(DataCallBack cb) { cb_ = cb; }
protected:
virtual void Process(std::string name) override {
int i = 0;
while (!stop_flag_) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
T data = i++;
if (cb_) cb_(data);
const int buffer_len = 128;
time_t t = time(0);
struct tm* now = localtime(&t);
char buffer[buffer_len];
strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
}
}
private:
DataCallBack cb_ = nullptr;
};
template <typename T>
class Consumer:public BaseTask {
public:
Consumer(): datas_(new SynchronizedQueue<T>), producer_(new Producer<T>){}
virtual ~Consumer() override { this->Stop(); }
Consumer(const Consumer & r) = default;
Consumer &operator=(const Consumer &r) = default;
virtual void Start() override {
if (worker_)
return;
else {
producer_->RegisterDataCallback(std::bind(&Consumer::DataCallback, this, std::placeholders::_1));
producer_->Start();
worker_.reset(new std::thread(std::bind(&Consumer::Process, this, std::string("Worker thread"))));
}
}
virtual void Stop() override {
if (!worker_)
return;
producer_->Stop();
stop_flag_ = true;
worker_->join();
worker_.reset();
stop_flag_ = false;
}
virtual void RegisterPrint(PrintFunc cb) override {
print_ = cb;
this->producer_->RegisterPrint(cb);
}
protected:
virtual void Process(std::string name) override {
while (!stop_flag_) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
T data;
this->datas_->dequeue(data);
const int buffer_len = 128;
time_t t = time(0);
struct tm* now = localtime(&t);
char buffer[buffer_len];
strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
}
}
void DataCallback(T& data) {
if (datas_)
datas_->enqueue(data);
}
private:
std::shared_ptr<SynchronizedQueue<T>> datas_ = nullptr;
std::shared_ptr<Producer<T> > producer_ = nullptr;
volatile bool stop_flag_ = false;
};
int main(int argc, char** argv)
{
Notify notify;
Consumer<int> consumer_;
consumer_.RegisterPrint(std::bind(&Notify::Print, ¬ify, std::placeholders::_1, std::placeholders::_2));
consumer_.Start();
while (1) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
CmakeLists文件
cmake_minimum_required(VERSION 3.0)
set(DEMO_NAME producer_consumer)
add_executable(${DEMO_NAME} producer_consumer.cpp)
set(MAJOR_VERSION "0")
set(MINOR_VERSION "0")
set(PATCH_VERSION "0")
set(VERSION_STRING "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread" )
target_compile_options(${DEMO_NAME}
PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall -Werror -Wno-c++11-long-long>
PRIVATE $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unknown-pragmas -Wall -Werror -Wno-c++11-long-long>
PRIVATE $<$<CXX_COMPILER_ID:Clang>:-Wno-unknown-pragmas -Wall -Werror -Wno-c++11-long-long>)