您的位置:首页 > 其它

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

2016-07-09 16:46 176 查看


问题描述

线程池将任务
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返回之后。


代码

https://github.com/spch2008/threadpool/blob/master/src/thread_locker.cpp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: