关系
workerThread和jobProvider是多对一的关系。
- workerThread.m_curJobProvider可以索引到workerThread当前所对应的jobProvider
- jobProvider.m_ownerBitmap可以索引到其名下的所有workerThread
jobProvider通过重写findJob函数负责提供工作,通过tryWakeOne()函数来唤醒一个休眠线程来执行,而workerThread在主运行函数内部通过调用findJob函数执行工作。
流程图
jobProvider
// Frame level job providers. FrameEncoder and Lookahead derive from
// this class and implement findJob()
class JobProvider
{
public:
ThreadPool* m_pool; // 所在的thread pool
sleepbitmap_t m_ownerBitmap; // 当前jobProvider所拥有的线程的位图
int m_jpId; // job id
int m_sliceType; // slice类型,一定意义上代表当前jobProvider的优先级
bool m_helpWanted; // 是否需要帮助
bool m_isFrameEncoder; /* rather ugly hack, but nothing better presents itself */
JobProvider()
: m_pool(NULL)
, m_ownerBitmap(0)
, m_jpId(-1)
, m_sliceType(INVALID_SLICE_PRIORITY)
, m_helpWanted(false)
, m_isFrameEncoder(false)
{}
virtual ~JobProvider() {}
// Worker threads will call this method to perform work
// jobProvider提供给workerThread执行的作业
virtual void findJob(int workerThreadId) = 0;
// Will awaken one idle thread, preferring a thread which most recently
// performed work for this provider.
// 尝试唤醒一个sleeping thread来执行当前的job
void tryWakeOne() {
// 首先在jobProvider名下的线程里找,若无则在所有线程池里找
int id = m_pool->tryAcquireSleepingThread(m_ownerBitmap, ALL_POOL_THREADS);
//获取线程失败,当前jobProvider需要帮助
if (id < 0)
{
m_helpWanted = true;
return;
}
// 若获取成,则得到获取的work thread
WorkerThread& worker = m_pool->m_workers[id];
//若获取的WorkerThread的jobProvider不是当前job,建立他们的关系
if (worker.m_curJobProvider != this) /* poaching */
{
// 构造当前线程的位图
sleepbitmap_t bit = (sleepbitmap_t)1 << id;
// 在当前线程的jobProvider所拥有的线程位图中,取消掉当前线程的拥有
SLEEPBITMAP_AND(&worker.m_curJobProvider->m_ownerBitmap, ~bit);
// 将当前jobProvider给分配的获取的workThread
worker.m_curJobProvider = this;
// 在当前jobProvider所拥有的线程位图,勾上当前线程
SLEEPBITMAP_OR(&worker.m_curJobProvider->m_ownerBitmap, bit);
}
// 唤醒获取的线程来执行job
worker.awaken();
}
};
workerThread
/*
工作线程
*/
class WorkerThread : public Thread
{
private:
ThreadPool& m_pool; // 线程所隶属的线程池
int m_id; // 线程id
Event m_wakeEvent; // 生产者消费者模型,这里把线程当作临界资源
WorkerThread& operator =(const WorkerThread&);
public:
JobProvider* m_curJobProvider;
BondedTaskGroup* m_bondMaster;
// 构造函数,初始化当前线程的隶属线程池和线程id
WorkerThread(ThreadPool& pool, int id) : m_pool(pool), m_id(id) {}
virtual ~WorkerThread() {}
// 这里把线程当作临界资源,唤醒当前线程
void awaken() { m_wakeEvent.trigger(); }
// 线程运行的主函数
void threadMain() {
THREAD_NAME("Worker", m_id);
#if _WIN32
// 给当前线程设置优先级为BELOW_NORMAL
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
#else
__attribute__((unused)) int val = nice(10);
#endif
// 将当前线程归属到m_pool线程池中
m_pool.setCurrentThreadAffinity();
// 构造当前线程的位图
sleepbitmap_t idBit = (sleepbitmap_t)1 << m_id;
// 将所在线程池的第一个jobPovider分配给当前线程,与之对应
m_curJobProvider = m_pool.m_jpTable[0];
m_bondMaster = NULL;
// 在线程对应的jobProvider的线程位图上勾选本线程
SLEEPBITMAP_OR(&m_curJobProvider->m_ownerBitmap, idBit);
// 在线程池sleep位图上添加本线程,并睡眠当前线程,
// 等待jobProvider进行awaken
SLEEPBITMAP_OR(&m_pool.m_sleepBitmap, idBit);
m_wakeEvent.wait();
// 若线程池活跃,开始占用线程资源,执行线程主函数循环
// 这里可以看到,线程的整个生命周期与线程池同步,
// 线程池活跃则线程存在(可能在工作也可能在sleep)
// 线程池失活则线程消亡
while (m_pool.m_isActive)
{
// 先检查当前线程是否被征用,若被征用到m_bondMaster则执行task
if (m_bondMaster)
{
// 执行m_bondMaster的task
m_bondMaster->processTasks(m_id);
// 执行完毕线程退出,m_exitedPeerCount累加
m_bondMaster->m_exitedPeerCount.incr();
// 置空
m_bondMaster = NULL;
}
// 按照优先级,不断的执行jobProvider的工作,
// 直到没有需要help的jobProvider为止,
do
{
/* do pending work for current job provider
jobProvider带着当前workerThread去执行工作 */
m_curJobProvider->findJob(m_id);
/* if the current job provider still wants help, only switch to a
* higher priority provider (lower slice type). Else take the first
* available job provider with the highest priority
#define X265_TYPE_AUTO 0x0000 // Let x265 choose the right type
#define X265_TYPE_IDR 0x0001
#define X265_TYPE_I 0x0002
#define X265_TYPE_P 0x0003
#define X265_TYPE_BREF 0x0004 // Non-disposable B-frame
#define X265_TYPE_B 0x0005 */
// 若当前jobProvider需要帮助则返回其sliceType作为优先级,否则优先级最低
// 也就是说优先级IDR > I > P > BREF > B > INVALID_SLICE_PRIORITY + 1
int curPriority = (m_curJobProvider->m_helpWanted) ? m_curJobProvider->m_sliceType :
INVALID_SLICE_PRIORITY + 1;
// 遍历workerThread所在线程池的所有jobProvider
// 寻找需要帮助且优先级高于自己的jobProvider的最高优先级nextProvider
int nextProvider = -1;
for (int i = 0; i < m_pool.m_numProviders; i++)
{
if (m_pool.m_jpTable[i]->m_helpWanted &&
m_pool.m_jpTable[i]->m_sliceType < curPriority)
{
nextProvider = i;
curPriority = m_pool.m_jpTable[i]->m_sliceType;
}
}
// 若找到了,且不是当前线程对应的jobProvider,
// 则将该jobProvider与当前workerThread绑定关系
if (nextProvider != -1 && m_curJobProvider != m_pool.m_jpTable[nextProvider])
{
// 在当前wokerThread对应的jobProvider的线程位图中取消勾选当前线程
SLEEPBITMAP_AND(&m_curJobProvider->m_ownerBitmap, ~idBit);
// 将找到的jobProvider与当前线程绑定
m_curJobProvider = m_pool.m_jpTable[nextProvider];
// 在新的jobProvider线程位图中勾选当前线程
SLEEPBITMAP_OR(&m_curJobProvider->m_ownerBitmap, idBit);
}
} while (m_curJobProvider->m_helpWanted);
/* While the worker sleeps, a job-provider or bond-group may acquire this
* worker's sleep bitmap bit. Once acquired, that thread may modify
* m_bondMaster or m_curJobProvider, then waken the thread
* 在线程池sleep位图上添加本线程,并睡眠当前线程
* 等待jobProvider进行awaken */
SLEEPBITMAP_OR(&m_pool.m_sleepBitmap, idBit);
m_wakeEvent.wait();
}
// 线程退出,在线程池的sleep位图中勾选当前线程
SLEEPBITMAP_OR(&m_pool.m_sleepBitmap, idBit);
}
};