问题描述
线程池将任务Task
添加到工作队列中,该队列使用STL List
实现。每次添加任务的时候,都需要获取线程锁,然后操作队列。
template <typename Item>
void ThreadQueue<Item>::Push(const Item &item)
{
{
ThreadLocker::Locker lock(&_locker);
_queue.push_back(item);
}
_locker.Signal();
}
问题来了,如何实现一个批量插入接口?
template <typename Item, typename Type>
void ThreadQueue<Item, Type>::Push(const QueueType &queue)
{
int notify_cnt = 0;
{
ThreadLocker::Locker lock(&_locker);
typename QueueType::const_iterator iter = queue.begin();
for ( ; iter != queue.end(); iter++)
{
_queue.push_back(*iter);
notify_cnt += 1;
}
}
for (int i = 0; i < notify_cnt; i++)
{
_locker.Signal();
}
}
批量操作,需要记录添加item的数量,在添加完成之后,进行Signal,通知工作线程,有新的任务到来。但这非常不方便,在任务需要批量操作的时候,都需要计数器。换个思路,能不能将计数器搬到锁管理类内,在解锁的时候,自动进行通知呢?
/* 理想代码 */
template <typename Item, typename Type>
void ThreadQueue<Item, Type>::Push(const QueueType &queue)
{
ThreadLocker::Locker lock(&_locker);
typename QueueType::const_iterator iter = queue.begin();
for ( ; iter != queue.end(); iter++)
{
_queue.push_back(*iter);
_locker.Notify();
}
}
解决方法
在锁管理类ThreadLocker
中,引入计数器_notify_num
。Notify
的时候,进行Signal操作,而仅仅是将计数器自增,在解锁的时候,进行实际操作。
/* 计数器自增 */
void ThreadLocker::Notify()
{
if (_notify_num != -1)
{
_notify_num += 1;
}
}
/* 解锁操作 */
void ThreadLocker::UnLock()
{
_thread_mutex.UnLock();
NotifyImpl();
}
/* 实际通知 */
void ThreadLocker::NotifyImpl()
{
if (_notify_num != 0)
{
if (_notify_num == -1)
{
BroadCast();
}
else
{
for (int i = 0; i < _notify_num; i++)
{
Signal();
}
}
_notify_num = 0;
}
}
NOTE: 在获取锁的时候,notify_num必须清0,这样,在notify的时候,自增才有效。获取锁的时机不仅在Lock函数,还在Wait、TimeWait返回之后。