SafeQueue.h
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <unistd.h>
#include <mutex>
#include <condition_variable>
#include <pthread.h>
template <typename T>
class SafeQueue {
public:
using lock_type = std::unique_lock<std::mutex>;
public:
SafeQueue() = default;
// 手动添加拷贝构造
SafeQueue(const SafeQueue& other)
{
// std::lock_guard<std::mutex> lock(other.mutex_);
lock_type lock{mutex_};
queue_ = other.queue_;
}
~SafeQueue() = default;
template<typename IT>
void push(IT &&item) {
static_assert(std::is_same<T, std::decay_t<IT>>::value, "Item type is not convertible!!!");
{
lock_type lock{mutex_};
queue_.emplace(std::forward<IT>(item));
}
cv_.notify_one();
}
auto pop() -> T {
lock_type lock{mutex_};
cv_.wait(lock, [&]() { return !queue_.empty(); });
auto front = std::move(queue_.front());
queue_.pop();
return front;
}
// - `empty()`:检查队列是否为空。
// 通过创建互斥锁对象,锁定临界区并使用STL `queue::empty()` 成员函数检查元素是否为空来实现。
bool empty() const {
lock_type lock{mutex_};
return queue_.empty();
}
// - `size()`:返回队列中元素的数量。
// 通过创建互斥锁对象,锁定临界区并使用STL `queue::size()` 成员函数返回队列中元素的数量来实现。
size_t size() const {
lock_type lock{mutex_};
return queue_.size();
}
// - `swap()`:用另一个队列对象交换这个队列对象的内容。
// 由于交换操作涉及两个不同的队列对象,因此需要创建两个互斥锁对象分别锁定两个队列对象,
// 然后使用STL `queue::swap()` 成员函数在两个队列对象之间交换内容来实现。
void swap(SafeQueue<T>& other) {
lock_type lock1{mutex_, std::defer_lock};
lock_type lock2{other.mutex_, std::defer_lock};
std::lock(lock1, lock2);
std::swap(queue_, other.queue_);
}
// - `clear()`:清空队列中的所有元素。
// 通过创建互斥锁对象,锁定临界区并使用STL `queue::swap()` 成员函数在队列对象中交换备用队列来实现。
void clear() {
lock_type lock{mutex_};
std::queue<T>().swap(queue_);
}
private:
std::queue<T> queue_;
mutable std::mutex mutex_;
// std::mutex mutex_;
std::condition_variable cv_;
};
DataBase.h
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <mutex>
#include <vector>
#include "SafeQueue.h"
using namespace std;
template<typename T>
using SafeQueue2D = SafeQueue<SafeQueue<T>>;
SafeQueue2D<int> testQ;
void init()
{
for (int i = 0; i < 5; i++)
{
SafeQueue<int> row;
for (int j = 0; j < 5; j++)
{
row.push(j + i * 5);
}
testQ.push(row);
}
}
void print()
{
init();
std::ostringstream ss;
while (!testQ.empty()) {
auto row = testQ.pop();
while (!row.empty()) {
ss << row.pop() << " ";
}
ss << '\n'; // 一行结束
}
std::cout << ss.str() << std::endl;
}
template <typename T>
class DataBase {
public:
DataBase() {
// m_queue.
}
// T & getData(int type) const;
// template <typename T>
T& getData(int type) const {
if(type == m_ulinkMsgType) {
if(!m_dataulink.empty()) {
return m_dataulink.back();
} else {
throw std::out_of_range("No data available for requested type");
}
} else if(type == m_dlinkMsgType) {
if(!m_datadlink.empty()) {
return m_datadlink.back();
} else {
throw std::out_of_range("No data available for requested type");
}
} else {
throw std::invalid_argument("Invalid data type");
}
}
// setData(int type, const T &data);
void setData(int type, const T &data) {
if(type == m_ulinkMsgType) {
m_dataulink.push_back(data);
} else if(type == m_dlinkMsgType) {
m_datadlink.push_back(data);
} else {
throw std::invalid_argument("Invalid data type");
}
}
public:
static SafeQueue<SafeQueue<T>> m_queue;
static vector<T> m_dataulink;
static vector<T> m_datadlink;
static int m_ulinkMsgType;
static int m_dlinkMsgType;
// std::mutex m_mutex;
};
// 声明模板类中的静态成员变量
template <typename T>
SafeQueue<SafeQueue<T>> DataBase<T>::m_queue;
template <typename T>
vector<T> DataBase<T>::m_dataulink;
template <typename T>
vector<T> DataBase<T>::m_datadlink;
template <typename T>
int DataBase<T>::m_ulinkMsgType = 1;
template <typename T>
int DataBase<T>::m_dlinkMsgType = 2;
Config.h
#pragma once
#include <iostream>
typedef enum tag_enum_ulink_ {
DB_ULINK_TYPE0 = 0,
DB_ULINK_TYPE1,
DB_ULINK_TYPE2,
DB_ULINK_TYPE3,
DB_ULINK_TYPE4,
DB_ULINK_TYPE5,
} ULinkDataType;
typedef enum tag_enum_dlink_ {
DB_DLINK_TYPE0 = 0,
DB_DLINK_TYPE1,
DB_DLINK_TYPE2,
DB_DLINK_TYPE3,
DB_DLINK_TYPE4,
DB_TYPE5,
} DLinkDataType;
main.c
#include <iostream>
#include <string>
#include <cstring>
#include "DataBase.h"
#include "Config.h"
int main()
{
std::cout << "hello c++" << std::endl;
// DataBase<int> db;
// db.m_queue[0].push(1);
print();
try {
// 创建一个DataBase类的实例化对象 string类型
DataBase<std::string> db;
// 设置向量中的数据
db.setData(DataBase<std::string>::m_ulinkMsgType, "this is a string for ulink Msg.");
db.setData(DataBase<std::string>::m_dlinkMsgType, "this is a string for dlink Msg.");
// 获取并输出向量中的数据
std::cout << db.getData(DataBase<std::string>::m_ulinkMsgType) << std::endl; // 输出:this is a string for ulink Msg.
std::cout << db.getData(DataBase<std::string>::m_dlinkMsgType) << std::endl; // 输出:this is a string for dlink Msg.
// 尝试获取一个不存在的数据类型会抛出异常
db.getData(3); // 输出:Invalid data type
} catch(const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
测试结果:
hello c++
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
this is a string for ulink Msg.
this is a string for dlink Msg.
Error: Invalid data type
根据上述声明,可以实现`getData()`和`setData()`方法的代码如下:
```c++
template <typename T>
T& DataBase<T>::getData(int type) const {
if(type == m_ulinkMsgType) {
if(!m_dataulink.empty()) {
return m_dataulink.back();
} else {
throw std::out_of_range("No data available for requested type");
}
} else if(type == m_dlinkMsgType) {
if(!m_datadlink.empty()) {
return m_datadlink.back();
} else {
throw std::out_of_range("No data available for requested type");
}
} else {
throw std::invalid_argument("Invalid data type");
}
}
template <typename T>
void DataBase<T>::setData(int type
, const T &data) {
if(type == m_ulinkMsgType) {
m_dataulink.push_back(data);
} else if(type == m_dlinkMsgType) {
m_datadlink.push_back(data);
} else {
throw std::invalid_argument("Invalid data type");
}
}
```
`getData()`方法接受一个整数类型参数,表示要获取的数据类型。如果请求的数据类型为`m_ulinkMsgType`或`m_dlinkMsgType`(存储在静态成员变量中),则分别尝试从`m_dataulink`或`m_datadlink`向量的末尾获取数据,并返回。如果所请求的向量为空则抛出异常。
`setData()`方法接受要设置的数据及其类型参数。如果类型参数为`m_ulinkMsgType`或`m_dlinkMsgType`,则向对应的向量中插入数据。
以下是一个示例,展示如何使用`DataBase`类并测试其实现:
```c++
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include "DataBase.h"
// 声明模板类中的静态成员变量
template <typename T>
SafeQueue<SafeQueue<T>> DataBase<T>::m_queue;
template <typename T>
vector<T> DataBase<T>::m_dataulink;
template <typename T>
vector<T> DataBase<T>::m_datadlink;
template <typename T>
int DataBase<T>::m_ulinkMsgType = 1;
template <typename T>
int DataBase<T>::m_dlinkMsgType = 2;
int main() {
try {
// 创建一个DataBase类的实例化对象 string类型
DataBase<std::string> db;
// 设置向量中的数据
db.setData(DataBase<std::string>::m_ulinkMsgType, "this is a string for ulink Msg.");
db.setData(DataBase<std::string>::m_dlinkMsgType, "this is a string for dlink Msg.");
// 获取并输出向量中的数据
std::cout << db.getData(DataBase<std::string>::m_ulinkMsgType) << std::endl; // 输出:this is a string for ulink Msg.
std::cout << db.getData(DataBase<std::string>::m_dlinkMsgType) << std::endl; // 输出:this is a string for dlink Msg.
// 尝试获取一个不存在的数据类型会抛出异常
db.getData(3); // 输出:Invalid data type
} catch(const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
```
在这个示例中,我们首先创建了一个`DataBase<std::string>`的实例化对象,并将两个字符串存储到`m_dataulink`和`m_datadlink`向量中,分别使用`setData()`来设置这两个向量中的数据。
然后我们使用`getData()`方法分别获取这两个向量中的数据,并打印结果。最后,我们测试获取一个不存在的类型时是否引发异常。如果存在异常,则捕获并在标准错误流上输出。
需要注意的是,这个示例只测试了`DataBase`类的`setData()`和`getData()`方法,实际上,这里也只有`整数int`类型一个成员变量,而使用时,需要根据实际情况进行更多类型的测试。