class ThreadPool
{
public:
sleepbitmap_t m_sleepBitmap;
int m_numProviders;
int m_numWorkers;
void* m_numaMask; // node mask in linux, cpu mask in windows
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_WIN7
GROUP_AFFINITY m_groupAffinity;
#endif
bool m_isActive;
JobProvider** m_jpTable;
WorkerThread* m_workers;
ThreadPool();
~ThreadPool();
bool create(int numThreads, int maxProviders, uint64_t nodeMask);
bool start();
void stopWorkers();
void setCurrentThreadAffinity();
void setThreadNodeAffinity(void *numaMask);
int tryAcquireSleepingThread(sleepbitmap_t firstTryBitmap, sleepbitmap_t secondTryBitmap);
int tryBondPeers(int maxPeers, sleepbitmap_t peerBitmap, BondedTaskGroup& master);
static ThreadPool* allocThreadPools(s265_param* p, int& numPools, bool isThreadsReserved);
static int getCpuCount();
static int getNumaNodeCount();
static void getFrameThreadsCount(s265_param* p,int cpuCount);
};
/* Any worker thread may enlist the help of idle worker threads from the same
* job provider. They must derive from this class and implement the
* processTasks() method. To use, an instance must be instantiated by a worker
* thread (referred to as the master thread) and then tryBondPeers() must be
* called. If it returns non-zero then some number of slave worker threads are
* already in the process of calling your processTasks() function. The master
* thread should participate and call processTasks() itself. When
* waitForExit() returns, all bonded peer threads are guaranteed to have
* exitied processTasks(). Since the thread count is small, it uses explicit
* locking instead of atomic counters and bitmasks */
class BondedTaskGroup
{
public:
Lock m_lock;
ThreadSafeInteger m_exitedPeerCount;
int m_bondedPeerCount;
int m_jobTotal;
int m_jobAcquired;
BondedTaskGroup() { m_bondedPeerCount = m_jobTotal = m_jobAcquired = 0; }
/* Do not allow the instance to be destroyed before all bonded peers have
* exited processTasks() */
~BondedTaskGroup() { waitForExit(); }
/* Try to enlist the help of idle worker threads on most recently associated
* with the given job provider and "bond" them to work on your tasks. Up to
* maxPeers worker threads will call your processTasks() method. */
int tryBondPeers(JobProvider& jp, int maxPeers)
{
int count = jp.m_pool->tryBondPeers(maxPeers, jp.m_ownerBitmap, *this);
m_bondedPeerCount += count;
return count;
}
/* Try to enlist the help of any idle worker threads and "bond" them to work
* on your tasks. Up to maxPeers worker threads will call your
* processTasks() method. */
int tryBondPeers(ThreadPool& pool, int maxPeers)
{
int count = pool.tryBondPeers(maxPeers, ALL_POOL_THREADS, *this);
m_bondedPeerCount += count;
return count;
}
/* Returns when all bonded peers have exited processTasks(). It does *NOT*
* ensure all tasks are completed (but this is generally implied). */
void waitForExit()
{
int exited = m_exitedPeerCount.get();
while (m_bondedPeerCount != exited)
exited = m_exitedPeerCount.waitForChange(exited);
}
/* Derived classes must define this method. The worker thread ID may be
* used to index into thread local data, or ignored. The ID will be between
* 0 and jp.m_numWorkers - 1 */
virtual void processTasks(int workerThreadId) = 0;
};
//线程池启动函数
bool ThreadPool::start()
{
m_isActive = true;
for (int i = 0; i < m_numWorkers; i++)
{
if (!m_workers[i].start())
{
m_isActive = false;
return false;
}
}
return true;
}
bool Thread::start()
{
if (pthread_create(&thread, NULL, ThreadShim, this))
{
thread = 0;
return false;
}
return true;
}
线程池类定义。
//PME启动
if (m_param->bDistributeMotionEstimation)
{
PME pme(*this, interMode, cuGeom, pu, puIdx);
pme.m_jobTotal = 0;
pme.m_jobAcquired = 1; /* reserve L0-0 or L1-0 */
uint32_t refMask = refMasks[puIdx] ? refMasks[puIdx] : (uint32_t)-1;
for (int list = 0; list < numPredDir; list++)
{
int idx = 0;
for (int ref = 0; ref < numRefIdx[list]; ref++)
{
if (!(refMask & (1 << ref)))
continue;
pme.m_jobs.ref[list][idx++] = ref;
pme.m_jobTotal++;
}
pme.m_jobs.refCnt[list] = idx;
/* the second list ref bits start at bit 16 */
refMask >>= 16;
}
if (pme.m_jobTotal > 2)
{
pme.tryBondPeers(*m_frame->m_encData->m_jobProvider, pme.m_jobTotal - 1);
processPME(pme, *this);
int ref = pme.m_jobs.refCnt[0] ? pme.m_jobs.ref[0][0] : pme.m_jobs.ref[1][0];
singleMotionEstimation(*this, interMode, pu, puIdx, 0, ref); /* L0-0 or L1-0 */
bDoUnidir = false;
ProfileCUScopeNamed(pmeWaitScope, interMode.cu, pmeBlockTime, countPMEMasters);
pme.waitForExit();
}
/* if no peer threads were bonded, fall back to doing unidirectional
* searches ourselves without overhead of singleMotionEstimation() */
}
//绑定当前对象
int tryBondPeers(JobProvider& jp, int maxPeers)
{
int count = jp.m_pool->tryBondPeers(maxPeers, jp.m_ownerBitmap, *this);
m_bondedPeerCount += count;
return count;
}
int ThreadPool::tryBondPeers(int maxPeers, sleepbitmap_t peerBitmap, BondedTaskGroup& master)
{
int bondCount = 0;
do
{
int id = tryAcquireSleepingThread(peerBitmap, 0); //获空闲线程
if (id < 0)
return bondCount;
m_workers[id].m_bondMaster = &master;
m_workers[id].awaken(); //唤醒 线程
bondCount++;
}
while (bondCount < maxPeers);
return bondCount;
}