1 queue原理
1.1 queue简述
std::queue: 模板类queue定义在<queue>头文件中。队列(Queue)是一个容器适配器(Container adaptor)类型,被特别设计用来运行于FIFO(First-in first-out)场景,在该场景中,只能从容器一端添加(Insert)元素,而在另一端提取(Extract)元素。只能从容器”后面”压进(Push)元素,从容器”前面”提取(Pop)元素。用来实现队列的底层容器必须满足顺序容器的所有必要条件。
queue模板类需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型。
图一
1.2 queue的API
queue 模板类的定义在<queue>头文件中。
与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类
型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
定义queue 对象的示例代码如下:
queue<int> q1;
queue<double> q2;
queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()
在上图一队列中,只能通过q.front()和q.back()访问a0和an,要想访问a1,必须调用q.pop(),将a0弹出队列,在调用q.front()进行访问。
1.3 代码实例1
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int e,n,m;
queue<int> q1;
for(int i=0;i<10;i++)
q1.push(i);
if(q1.empty())
cout<<"queue is empty.\n";
n=q1.size();
cout<<n<<endl;
m=q1.back();
cout<<m<<endl;
for(int j=0;j<n;j++)
{
e=q1.front();
cout<<e<<" ";
q1.pop();
}
cout<<endl;
if(q1.empty())
cout<<"queue is empty.\n";
return 0;
}
10
9
0 1 2 3 4 5 6 7 8 9
queue is empty.
1.4 代码实例2-string
{ // std::queue::emplace: C++11, Construct and insert element.
// Adds a new element at the end of the queue, after its current last element.
// The element is constructed in-place, i.e. no copy or move operations are performed.
// queue::push: inserts element at the end , queue::emplace: constructs element in-place at the end
// queue::pop: removes the first element
std::queue<std::string> myqueue;
myqueue.emplace("First sentence");
myqueue.emplace("Second sentence");
std::cout << "myqueue contains:\n";
while (!myqueue.empty()) {
std::cout << myqueue.front() << '\n';
myqueue.pop();
}
2 queue在多线程中应用
通过使用消息队列queue,可以实现多线程通信。以及一个线程频繁接收到消息,而已处理这个消息,需要耗费一点时间,处理消息阻塞当前线程,导致无法接到到新的消息,造成异常。因此额外开一个新的线程,此新线程只管处理消息,当前线程只管接收消息,接收后当前函数退出,处理其他任务,即可避免阻塞线程了。实现系统的稳定。
在处理为了避免数据冲突,需要用到锁和条件锁。
2.1 代码实例
static pthread_mutex_t onLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t onCond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t onMutex = PTHREAD_MUTEX_INITIALIZER;
std::queue<std::string> onMessageQueue;
//额外启动一个消息执行队列
void AppManager::starMessageThread(){
pthread_t id;
int ret = pthread_create(&id, NULL, (void *) onMessageExecuteThread, NULL);
pthread_detach(id);
if (ret != 0) {
APP_INFO("startProcessThread create pthread fail");
}
}
//消息处理线程,无消息时,进入休眠状态,不占用资源
static void * AppManager::onMessageExecuteThread()
{
prctl(PR_SET_NAME, (unsigned long)"onMessageExecuteThread");
while(1)
{
pthread_mutex_lock(&onLock);
pthread_cond_wait(&onCond, &onLock);//阻塞,等待条件
pthread_mutex_unlock(&onLock);
while(onMessageQueue.size() > 0)//处理完所有消息
{
pthread_mutex_lock(&onMutex);
std::string message = onMessageQueue.front();
onMessageQueue.pop();
pthread_mutex_unlock (&onMutex);
onProcessMessage(message); //实际的消息处理函数,这样与发送消息的线程分开,避免占用发送消息线程的时间
}
}
return NULL;
}
//另一个线程的回调函数,通过这个函数发送消息
bool AppManager::onSendMessage(const std::string &message) {
pthread_mutex_lock (&onMutex);
onMessageQueue.push(message);
pthread_mutex_unlock (&onMutex);
pthread_mutex_lock (&onLock);
pthread_cond_signal(&onCond);
pthread_mutex_unlock (&onLock);
return true;
}