STL-queue篇
2019-10-09 本文已影响0人
ninedreams
简介
queue队列是一种先进先出的队列
用法
C++队列queue模板类的定义在<queue>头文件中,queue 模板类需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
C++队列Queue类成员函数如下:
back() //返回最后一个元素
empty() //如果队列空则返回真
front() //返回第一个元素
pop() //弹出第一个元素
push() //在末尾加入一个元素
size() //返回队列中元素的个数
emplace() //C++11 原地构造一个元素并插入队列
swap() //C++11 交换内容
成员函数不多,且都简单明了,其中最后两个emplace和swap是C++11中才有的函数。
简单示例
#include <queue>
#include <iostream>
int main(int argc, char** argv) {
std::queue<int> q_int;
q_int.push(1);
q_int.push(2);
q_int.push(3);
std::cout << q_int.front() << " " << q_int.back() << " " << q_int.size() << std::endl;
q_int.pop();
std::cout << q_int.front() << " " << q_int.back() << " " << q_int.size() << std::endl;
return 0;
}
运行结果如下:
先从队列尾部加入
1 2 3
,可以看到队列front()
是1,队列back()
是3,size()
是3。然后使用pop()
之后,队列头部就是2了,尾部没有变化还是3,size()
也变成了2。
优先队列priority_queue
和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队,函数与队列基本一致。
top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容
定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list,STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆,列子如下:
#include<iostream>
#include <queue>
using namespace std;
int main(int argc, char** argv) {
//对于基础类型 默认是大顶堆
priority_queue<int> a;
//等同于 priority_queue<int, vector<int>, less<int> > a;
// 这里一定要有空格,不然成了右移运算符↓
priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆
priority_queue<string> b;
for (int i = 0; i < 5; i++) {
a.push(i);
c.push(i);
}
while (!a.empty()) {
cout << a.top() << ' ';
a.pop();
}
cout << endl;
while (!c.empty()) {
cout << c.top() << ' ';
c.pop();
}
cout << endl;
b.push("abcd");
b.push("abcdef");
b.push("cba");
while (!b.empty()) {
cout << b.top() << ' ';
b.pop();
}
cout << endl;
return 0;
}
编译出来的结果:
使用queue实现一个线程安全的redis连接池
连接池是我们在开发工作中都会用到的一种方法或理念。下面是使用queue
和mutex
实现的一个简单的redis连接池,线程安全。
#include <queue>
#include <mutex>
#include <sstream>
#include <string>
#include "hiredis/hiredis.h"
using namesapce std;
class RedisPool {
private:
string redis_host;
int redis_port;
string auth;
int max;
int curConnNum;
queue<redisContext*> redis_queue;
mutex lock;
private:
void init();
redisContext* createConn();
redisContext* getConn();
void clear();
void putConn(redisContext* conn);
public:
bool redisSendCmd(const string& cmd, string& res);
bool redisSendCmd(const char* cmd, int len, string& res);
public:
RedisPool();
void redisPoolInit(const char* host,
const int port,
const char* auth,
int max = 100);
~RedisPool();
};
RedisPool::RedisPool() {}
RedisPool::~RedisPool() {
clear();
}
void RedisPool::redisPoolInit(const char* host,
const int port,
const char* auth,
int max) {
this->redis_host = host;
this->redis_port = port;
this->auth = auth;
this->max = max;
init();
}
redisContext* RedisPool::createConn() {
redisContext* redis_conn = redisConnect(redis_host.c_str(), redis_port);
if (redis_conn == NULL || redis_conn->err) {
if (redis_conn) {
std::cout << " Redis conn error: " << redis_conn->errstr << std::endl;
} else {
std::cout<< " Redis conn error: Can't allocate redis context" << std::endl;
}
if (redis_conn != NULL) {
delete redis_conn;
}
return NULL;
}
if (auth != "") {
ostringstream oss;
oss << "AUTH " << auth;
redisReply* reply = (redisReply*)redisCommand(redis_conn, oss.str().c_str());
if (reply == NULL) {
std::cout << oss.str() << " failed! return NULL";
}
if (reply->type == REDIS_REPLY_STATUS &&
strcmp(reply->str, "OK") == 0) {
freeReplyObject(reply);
} else {
std::cout << oss.str() << " failed! return not OK. ret: " << reply->str;
freeReplyObject(reply);
delete redis_conn;
return NULL;
}
}
return redis_conn;
}
redisContext* RedisPool::getConn() {
redisContext* c(NULL);
lock.lock();
while (redis_queue.size() <= 0 && curConnNum >= max) {
lock.wait();
}
if (redis_queue.size() > 0) {
c = redis_queue.front();
redis_queue.pop();
lock.unlock();
// TEST
// redisReply* reply = redisCommand(c, "PING");
// if (reply->type == REDIS_REPLY_STRING &&
// strcmp(reply->str, "PONG") == 0) {
// freeReplyObject(reply);
// // OK
// } else {
// freeReplyObject(reply);
// // delete
// delete c;
// c = createConn();
// }
} else if (curConnNum < max) {
lock.unlock();
c = createConn();
lock.lock();
++curConnNum;
lock.unlock();
} else {
return NULL;
lock.unlock();
}
return c;
}
void RedisPool::putConn(redisContext* conn) {
lock.lock();
redis_queue.push(conn);
lock.signal();
lock.unlock();
}
void RedisPool::init() {
clear();
curConnNum = 0;
}
void RedisPool::clear() {
lock.lock();
while (!redis_queue.empty()) {
delete redis_queue.front();
redis_queue.pop();
}
curConnNum = 0;
lock.unlock();
}
bool RedisPool::redisSendCmd(const char* cmd, int len, string& res) {
redisContext* c = nullptr;
c = getConn();
if (c == NULL) {
c = getConn();
if (c == NULL) {
return false;
}
}
int ret = redisAppendFormattedCommand(c, cmd, len);
if (ret != REDIS_OK) {
putConn(c);
std::cout << "redisAppendFormattedCommand failed! Ret : " << ret << std::endl;
return false;
}
redisReply* reply = nullptr;
if (redisGetReply(c, (void**)&reply) != REDIS_OK) {
putConn(c);
LOG(ERROR) << "redisGetReply failed! Ret not REDIS_OK.";
freeReplyObject(reply);
return false;
}
if (reply == nullptr) {
putConn(c);
std::cout << "redisGetReply failed! Return reply nullptr." << std::endl;
freeReplyObject(reply);
return false;
}
if (reply->type == REDIS_REPLY_STRING || reply->type == REDIS_REPLY_STATUS) {
putConn(c);
res = reply->str;
freeReplyObject(reply);
return true;
}
if (reply->type == REDIS_REPLY_NIL) {
putConn(c);
freeReplyObject(reply);
return false;
}
putConn(c);
std::cout << "send redis cmd failed! return not STRING or OK. return type: " << reply->type << ", return str: " << reply->str << std::endl;
freeReplyObject(reply);
return false;
}