关键技术点:
- 多线程环境下,cout因为拥有缓冲buffer,可能会写出失败,可以先使用stringstream进行缓存,在输出对象销毁时,在析构函数中使用std::cerr输出
- C++ 11 条件变量和互斥体的简单用法
- C++ 11 多线程的简单用法
实现代码
scout.hpp
#ifndef _SCOUT_HPP_
#define _SCOUT_HPP_
#include <mutex>
#include <iostream>
#include <sstream>
class Scout {
std::ostringstream st;
// Endl结束符的形式
using endlFunc = std::ostream& (*)(std::ostream&);
public:
// 处理普通模板类输出
template <typename T>
Scout& operator<<(const T& t) {
st << t;
return *this;
}
// 处理换行符
Scout& operator<<(endlFunc endlF) {
st << endlF;
return *this;
}
~Scout() {
std::string s = st.str();
// std::cerr不存buffer 直接输出
std::cerr << s;
}
};
// 定义一个宏,方便输出
#define scout Scout()
#endif
sync_queue.hpp
#ifndef _SYNC_QUEUE_HPP_
#define _SYNC_QUEUE_HPP_
#include <list>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <iostream>
#include "scout.hpp"
template <typename T>
class SyncQueue {
private:
// 队列缓冲区已满
bool isFull() const {
return m_queue.size() == m_maxSize;
}
// 队列缓冲区为空
bool isEmpty() const {
return m_queue.empty();
}
public:
SyncQueue(int maxSize): m_maxSize(maxSize) {}
// 入队操作
void Put(const T& x) {
std::lock_guard<std::mutex> lock(m_mutex);
while(isFull()) {
scout << "缓冲区满了,需要等待..." << std::endl;
m_notFull.wait(m_mutex);
}
m_queue.emplace_back(x);
m_notEmpty.notify_one();
}
// 出队操作
void Take(T& x) {
std::lock_guard<std::mutex> lock(m_mutex);
while(isEmpty()) {
scout << "缓冲区为空了,需要等待..." << std::endl;
m_notEmpty.wait(m_mutex);
}
x = m_queue.front();
m_queue.pop_front();
m_notFull.notify_one();
}
// 带锁的Empty版本
bool Empty() {
std::lock_guard<std::mutex> lock(m_mutex);
return m_queue.empty();
}
// 带锁的Full版本
bool Full() {
std::lock_guard<std::mutex> lock(m_mutex);
return m_queue.size() == m_maxSize;
}
// 带锁的size版本
int Size() {
std::lock_guard<std::mutex> lock(m_mutex);
return m_queue.size();
}
// 不带锁的size版本
int Count() {
return m_queue.size();
}
private:
std::list<T> m_queue; // 队列缓冲区
std::mutex m_mutex; // 互斥量和条件变量结合使用
std::condition_variable_any m_notEmpty; // 不为空的条件变量
std::condition_variable_any m_notFull; // 不为满的条件变量
int m_maxSize; // 同步队列的最大大小
};
#endif
main.cpp
#include "sync_queue.hpp"
#include <thread>
#include <iostream>
#include <mutex>
#include <cstdlib>
using std::cout;
using std::endl;
SyncQueue<int> syncQueue(5);
void PutDatas() {
for(int i=0; i<20; i++) {
syncQueue.Put(888);
}
}
void TakeDatas() {
int x = 0;
for(int i=0; i<20; i++) {
syncQueue.Take(x);
scout << x << " ";
}
scout << endl;
}
int main(void) {
std::thread t1(PutDatas);
std::thread t2(TakeDatas);
t1.join();
t2.join();
cout << "请按任意键继续..." << endl;
getchar();
return 0;
}
程序输出如下
图片.png
网友评论