#include <iostream>
#include <thread>
#include <stdlib.h>
#include <unistd.h>
#include <queue>
#include <assert.h>
#include <mutex>
#include <condition_variable>
using namespace std;
///TMsgQue是模板类,可以实例化成各种消息
template<typename M>
class TMsgQue
{
public:
///创建消息队列
TMsgQue(int queueSize = 1024)
{
m_queueSize = queueSize;
};
virtual ~TMsgQue(){};
///sendMessage函数是存储消息的函数
///消息的存储和获取通过锁和条件变量来控制
///当消息队列为空并且wait为true时recvMessage是被条件变量阻塞的
///当消息队列为空并且wati为false是,recvMessage不会被阻塞
///当sendMessage的时候消息队列不为空条件变量唤醒阻塞的recvMessage函数
bool sendMessage (M& message)
{
unique_lock<mutex> locker(m_mutex);//锁
if(m_queue.size() >= (size_t)m_queueSize)
{
return false;
}
m_queue.push(message);
cond.notify_one();
return true;
};
///recvMessage是获取消息的函数
///如果消息队列为空并且wait为true,则该函数是被条件变量阻塞
///如果消息队列为空并且wait为false,则该函数返回false
///如果消息队列不为空,recvMessage会被唤醒
bool recvMessage (M& message, bool wait = true)
{
unique_lock<mutex> lock(m_mutex);
if (!wait)
{
if (m_queue.empty())
{
return false;
}
}
if (m_queue.empty())
{
cond.wait(lock);
}
message = m_queue.front();
m_queue.pop();
return true;
}
void clean()
{
std::unique_lock<std::mutex>lock(m_mutex);
int n = m_queue.size();
for(int i = 0; i < n; i++)
{
cond.wait(lock);
m_queue.pop_back();
}
}
/// 得到消息队列中消息个数
int size()
{
std::unique_lock<std::mutex>lock(m_mutex);
return m_queue.size();
}
/// 得到消息队列的最大长度
int getMaxSize()
{
std::unique_lock<std::mutex>lock(m_mutex);
return m_queueSize;
}
/// 得到消息队列的最大长度,将在下次SendMessage时生效
/// \param size 新的消息队列长度,可以比原来的大或者小
void setMaxSize(int size)
{
std::unique_lock<std::mutex>lock(m_mutex);
m_queueSize = size;
}
private:
typedef std::queue<M> Queue;
Queue m_queue;
std::mutex m_mutex;
condition_variable cond;
int m_queueSize;
};
///事件枚举
typedef enum Event
{
init = 1,
first = 2,
second = 3,
four = 4,
}Event;
///消息结构体
typedef struct Message
{
Event event;
std::string str;
int num;
///这里可以自定义数据类型,比如json,结构体等
}Message;
///生产者和消费者模式
///main函数是主线程,是生产者, Fun类的f函数是子线程,是消费者
///主线程通过消息队列给子线程发送消息,如果有消息,子线程就处理消息,否则子线程被条件变量阻塞,等待消息
class Fun
{
public:
void start()
{
m_bFlag = true;
}
void stop()
{
printf("Fun thread over..\n");
m_bFlag = false;
}
void f()
{
while(m_bFlag)
{
sleep(1);
Message m;
///消息统一出口函数,不会漏掉消息
///线程根据事件类型处理不同的消息
///当recvMessage的第二个参数是true并且没有收到消息, 线程就被条件变量阻塞住,不会往下执行,如果收到消息则ret=1就可以处理消息
///当recvMessage的第二个参数是false并且没有消息处理,ret=0,线程空转
///当recvMessage的第二个参数是false并且有消息,ret=1,线程处理消息
int ret = m_Message.recvMessage(m);
///int ret = m_Message.recvMessage(m, false);
if (ret)
{
if (m.event == init)
{
cout << "event:" << m.event << "\tstr:" << m.str << "\tnum:" << m.num << endl;
}
else if (m.event == first)
{
cout << "event:" << m.event << "\tstr:" << m.str << "\tnum:" << m.num << endl;
}
else if (m.event == second)
{
cout << "event:" << m.event << "\tstr:" << m.str << "\tnum:" << m.num << endl;
///在线程中也可以发送消息
Message m;
m.event = four;
m.str = "chanhui";
m.num = 1234;
m_Message.sendMessage(m);
}
else if (m.event == four)
{
cout << "event:" << m.event << "\tstr:" << m.str << "\tnum:" << m.num << endl;
}
}
printf("m_Message after size:%d\n", m_Message.size());
}
}
///消息统一入口函数,不会漏掉消息
void sendMessage(Event event, std::string str, int num)
{
printf("m_Message before size:%d\n", m_Message.size());
Message m;
m.event = event;
m.str = str;
m.num = num;
m_Message.sendMessage(m);
};
private:
bool m_bFlag;
TMsgQue<Message> m_Message;
};
int main()
{
Fun fun;
///开启线程f
fun.start();
std::thread t(&Fun::f, &fun);
Event event = init;
for(size_t i = 0; i < 10; i++)
{
if (i % 3 == 0)
{
event = init;
}
else if (i % 3 == 1)
{
event = first;
}
else if (i % 3 == 2)
{
event = second;
}
///主线程是生产者,调用消费者的sendMessage函数发消息给子线程处理
///子线程异步处理消息,不会影响主线程功能
fun.sendMessage(event, "hello", i);
}
while(1)
{}
fun.stop();
t.join();
return 0;
}