自己动手写线程池之锁的优化

来源:互联网 发布:收集用户行为数据 编辑:程序博客网 时间:2024/05/01 09:37

问题描述

线程池将任务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_numNotify的时候,进行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返回之后。

代码

https://github.com/spch2008/threadpool/blob/master/src/thread_locker.cpp

0 0