关于并发程序的交互,办法挺多,但是既要快速响应又要节省CPU的没什么太好的现成策略。我这里提个思路,大家探讨探讨。
分析
死循环,响应速度够快,但是浪费CPU,每个循环加上一个sleep(0)或者yield(),能省一些cpu,但是还是会很烫。
用事件触发(最省CPU),有可靠的消息机制的当然好,只是发一个信号的那种,存在错过信号的问题。因为一般只有在线程调用等待函数之后发出的信号才能被收到,工作线程正在工作时不能接收信号。由于并发特性,检测线程工作状态和发送信号之间可能是无限长的,实际发送的时候工作线程已经不是刚才检测到的状态了。
设计
我现在考虑使用这么个机制:
- 信号和标志位双触发机制
- 控制线程同时发送信号和设置标志位
- 工作线程循环处理,处理开始清除标志位,处理结束检查标志位,有标志位继续处理,没有则等待信号
- 唯一会错过的情形是控制线程的两步操作(设置和发送)刚好在工作线程的两步操作(检查和等待)之间,没找到办法把这两步合并为原子操作
- 所以又增加一个定时器,定时触发检查有没有工作要做,实际是信号、标志位、定时器三触发
代码
使用了C++11的新特性。
三个成员:
mutex m_work_mutex;//互斥锁condition_variable m_work_cv;//条件变量bool m_manual_active = false;//此标志位确保进程已经在处理时不会错过激活信号(如果线程不在等待中则信号会被忽略,导致处理被推迟到下次定时激活)
工作线程:
void _WorkThread(){thelog << "WorkThread" << endi;while (true){m_manual_active = false;//处理__Work();if (!m_manual_active){//等待数据unique_lock<mutex> lck(m_work_mutex);m_work_cv.wait(lck);thelog << "WorkThread被激活" << endi;}}}
激活工作线程:
m_work_cv.notify_one();m_manual_active = true;
这两句可以写成一个函数,方便控制线程调用。
定时器线程:
void _TimerThread(){thelog << "TimerThread" << endi;while (true){m_work_cv.notify_one();m_manual_active = true;//定时激活发送线程,避免发送线程无限期等待Sleep(1000);}}
至于起线程,C++11的thread太简单了:
//启动子线程m_work_thread = new thread(WorkThread, this);m_timer_thread = new thread(TimerThread, this);
由于线程函数不能依赖对象,所以套了一层壳:
static void WorkThread(类名* pMe){pMe->_WorkThread();}static void TimerThread(类名* pMe){pMe->_TimerThread();}
这样就把静态方法转换为普通方法了。
(这里是结束)