簡(jiǎn)介
queue隊(duì)列是一種先進(jìn)先出的隊(duì)列
用法
C++隊(duì)列queue模板類的定義在<queue>頭文件中,queue 模板類需要兩個(gè)模板參數(shù)齐帚,一個(gè)是元素類型,一個(gè)容器類型,元素類型是必要的,容器類型是可選的嘉蕾,默認(rèn)為deque 類型。
C++隊(duì)列Queue類成員函數(shù)如下:
back() //返回最后一個(gè)元素
empty() //如果隊(duì)列空則返回真
front() //返回第一個(gè)元素
pop() //彈出第一個(gè)元素
push() //在末尾加入一個(gè)元素
size() //返回隊(duì)列中元素的個(gè)數(shù)
emplace() //C++11 原地構(gòu)造一個(gè)元素并插入隊(duì)列
swap() //C++11 交換內(nèi)容
成員函數(shù)不多霜旧,且都簡(jiǎn)單明了错忱,其中最后兩個(gè)emplace和swap是C++11中才有的函數(shù)。
簡(jiǎn)單示例
#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;
}
運(yùn)行結(jié)果如下:
先從隊(duì)列尾部加入
1 2 3
挂据,可以看到隊(duì)列front()
是1以清,隊(duì)列back()
是3,size()
是3棱貌。然后使用pop()
之后玖媚,隊(duì)列頭部就是2了,尾部沒有變化還是3婚脱,size()
也變成了2今魔。
優(yōu)先隊(duì)列priority_queue
和queue不同的就在于我們可以自定義其中數(shù)據(jù)的優(yōu)先級(jí), 讓優(yōu)先級(jí)高的排在隊(duì)列前面,優(yōu)先出隊(duì)勺像,函數(shù)與隊(duì)列基本一致。
top 訪問隊(duì)頭元素
empty 隊(duì)列是否為空
size 返回隊(duì)列內(nèi)元素個(gè)數(shù)
push 插入元素到隊(duì)尾 (并排序)
emplace 原地構(gòu)造一個(gè)元素并插入隊(duì)列
pop 彈出隊(duì)頭元素
swap 交換內(nèi)容
定義:priority_queue<Type, Container, Functional>
Type 就是數(shù)據(jù)類型错森,Container 就是容器類型(Container必須是用數(shù)組實(shí)現(xiàn)的容器吟宦,比如vector,deque等等烹笔,但不能用 list扛邑,STL里面默認(rèn)用的是vector),F(xiàn)unctional 就是比較的方式导街,當(dāng)需要用自定義的數(shù)據(jù)類型時(shí)才需要傳入這三個(gè)參數(shù)瓦阐,使用基本數(shù)據(jù)類型時(shí)蜗侈,只需要傳入數(shù)據(jù)類型,默認(rèn)是大頂堆睡蟋,列子如下:
#include<iostream>
#include <queue>
using namespace std;
int main(int argc, char** argv) {
//對(duì)于基礎(chǔ)類型 默認(rèn)是大頂堆
priority_queue<int> a;
//等同于 priority_queue<int, vector<int>, less<int> > a;
// 這里一定要有空格踏幻,不然成了右移運(yùn)算符↓
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;
}
編譯出來的結(jié)果:使用queue實(shí)現(xiàn)一個(gè)線程安全的redis連接池
連接池是我們?cè)陂_發(fā)工作中都會(huì)用到的一種方法或理念。下面是使用queue
和mutex
實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的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;
}