将工作发送到 std::thread
Sending jobs to a std::thread
我是 std::thread 的新手,我很快意识到创建它们的成本非常高,至少在我的计算机上 运行 W7。
所以我决定创建我的线程并使用那段示例代码向它发送作业:http://en.cppreference.com/w/cpp/thread/condition_variable
我的代码运行良好,没有崩溃,但是我没有注意到性能有多大提升,所以我测量了作业完成时间与主线程检测到作业完成时间之间的差异(请参阅 WaitUntilJobFinished() )我注意到在极少数情况下时差超过 2 毫秒
有人看到代码有什么问题吗?
代码:
class CJobParameters
{
public:
};
typedef void (*CJobFunc)( const CJobParameters * );
class CThread
{
public:
void Start();
void WaitUntilJobDone();
void StartJob( CJobFunc inJobFunc, const CJobParameters * inJobParameters );
std::thread m_stdThread;
CJobFunc m_jobFunc = nullptr;
const CJobParameters * m_jobParameters = nullptr;
//std::atomic<bool> m_jobDone = true;
std::mutex m_mutex;
std::condition_variable m_cv;
__int64 m_jobDoneAt = 0;
__int64 m_threadJoinedAt = 0;
__int64 m_lostTime = 0;
};
class CThreads
{
public:
static void Start();
static CThread threadArray[ JOB_COUNT ];
};
void ThreadMain( CThread * inThread )
{
while ( true )
{
std::unique_lock<std::mutex> lk( inThread->m_mutex );
inThread->m_cv.wait(lk, [ inThread ]{return inThread->m_jobParameters != nullptr;});
if ( inThread->m_jobFunc )
{
(*inThread->m_jobFunc)( inThread->m_jobParameters );
inThread->m_jobFunc = nullptr;
inThread->m_jobParameters = nullptr;
inThread->m_jobDoneAt = COSToolbox::QuerySystemTime2();
}
lk.unlock();
inThread->m_cv.notify_one();
std::this_thread::sleep_for( std::chrono::nanoseconds(0) );
}
}
void CThread::StartJob( CJobFunc inJobFunc, const CJobParameters * inJobParameters )
{
std::lock_guard<std::mutex> lk( m_mutex );
m_jobFunc = inJobFunc;
m_jobParameters = inJobParameters;
m_cv.notify_one();
}
void CThread::Start()
{
m_stdThread = std::thread( ThreadMain, this );
}
void CThread::WaitUntilJobDone()
{
std::unique_lock<std::mutex> lk( m_mutex );
m_cv.wait(lk, [ this ]{return this->m_jobParameters == nullptr;});
m_threadJoinedAt = COSToolbox::QuerySystemTime2();
m_lostTime = m_threadJoinedAt - m_jobDoneAt;
LOG_INFO( "Thread joined with %f ms lost", (Float32)m_lostTime / 1000 );
}
CThread CThreads::threadArray[ JOB_COUNT ];
void CThreads::Start()
{
for ( Int32 i = 0; i < JOB_COUNT; ++i )
{
threadArray[i].Start();
}
}
void MyJobFunc( const CJobParameters * jobParameters )
{
// do job here
}
void main()
{
CThreads::Start();
while(true)
{
CJobParameters jobParametersArray[ JOB_COUNT ];
for ( Int32 i = 0; i < JOB_COUNT; ++i )
{
CThread & thread = CThreads::threadArray[ i ];
CJobParameters& jobParameters = jobParametersArray[ i ];
jobParameters.m_ // Fill in params
thread.StartJob( &MyJobFunc, &jobParameters );
}
for ( Int32 i = 0; i < JOB_COUNT; ++i )
{
CThread & thread = CThreads::threadArray[ i ];
// Prints 2 ms sometimes whith i = 0
thread.WaitUntilJobDone();
}
}
}
两件事:
您无条件地放弃了处理器时间,并且在某些旧版本的 windows 上,您放弃了整个进程,而不仅仅是线程:
std::this_thread::sleep_for( std::chrono::nanoseconds(0) );
这个 yield 是不必要的。我怀疑你这样做的原因是没有它你会得到一个自旋循环,这是因为你正在读取和写入单个条件变量。
您需要两个条件变量,一个用于未完成的工作,一个用于完成的工作。通常,侦听器会将条件变量或包含它的结构作为参数传递给线程函数,从而允许您从调度程序传递单个条件变量。
我是 std::thread 的新手,我很快意识到创建它们的成本非常高,至少在我的计算机上 运行 W7。 所以我决定创建我的线程并使用那段示例代码向它发送作业:http://en.cppreference.com/w/cpp/thread/condition_variable
我的代码运行良好,没有崩溃,但是我没有注意到性能有多大提升,所以我测量了作业完成时间与主线程检测到作业完成时间之间的差异(请参阅 WaitUntilJobFinished() )我注意到在极少数情况下时差超过 2 毫秒
有人看到代码有什么问题吗?
代码:
class CJobParameters
{
public:
};
typedef void (*CJobFunc)( const CJobParameters * );
class CThread
{
public:
void Start();
void WaitUntilJobDone();
void StartJob( CJobFunc inJobFunc, const CJobParameters * inJobParameters );
std::thread m_stdThread;
CJobFunc m_jobFunc = nullptr;
const CJobParameters * m_jobParameters = nullptr;
//std::atomic<bool> m_jobDone = true;
std::mutex m_mutex;
std::condition_variable m_cv;
__int64 m_jobDoneAt = 0;
__int64 m_threadJoinedAt = 0;
__int64 m_lostTime = 0;
};
class CThreads
{
public:
static void Start();
static CThread threadArray[ JOB_COUNT ];
};
void ThreadMain( CThread * inThread )
{
while ( true )
{
std::unique_lock<std::mutex> lk( inThread->m_mutex );
inThread->m_cv.wait(lk, [ inThread ]{return inThread->m_jobParameters != nullptr;});
if ( inThread->m_jobFunc )
{
(*inThread->m_jobFunc)( inThread->m_jobParameters );
inThread->m_jobFunc = nullptr;
inThread->m_jobParameters = nullptr;
inThread->m_jobDoneAt = COSToolbox::QuerySystemTime2();
}
lk.unlock();
inThread->m_cv.notify_one();
std::this_thread::sleep_for( std::chrono::nanoseconds(0) );
}
}
void CThread::StartJob( CJobFunc inJobFunc, const CJobParameters * inJobParameters )
{
std::lock_guard<std::mutex> lk( m_mutex );
m_jobFunc = inJobFunc;
m_jobParameters = inJobParameters;
m_cv.notify_one();
}
void CThread::Start()
{
m_stdThread = std::thread( ThreadMain, this );
}
void CThread::WaitUntilJobDone()
{
std::unique_lock<std::mutex> lk( m_mutex );
m_cv.wait(lk, [ this ]{return this->m_jobParameters == nullptr;});
m_threadJoinedAt = COSToolbox::QuerySystemTime2();
m_lostTime = m_threadJoinedAt - m_jobDoneAt;
LOG_INFO( "Thread joined with %f ms lost", (Float32)m_lostTime / 1000 );
}
CThread CThreads::threadArray[ JOB_COUNT ];
void CThreads::Start()
{
for ( Int32 i = 0; i < JOB_COUNT; ++i )
{
threadArray[i].Start();
}
}
void MyJobFunc( const CJobParameters * jobParameters )
{
// do job here
}
void main()
{
CThreads::Start();
while(true)
{
CJobParameters jobParametersArray[ JOB_COUNT ];
for ( Int32 i = 0; i < JOB_COUNT; ++i )
{
CThread & thread = CThreads::threadArray[ i ];
CJobParameters& jobParameters = jobParametersArray[ i ];
jobParameters.m_ // Fill in params
thread.StartJob( &MyJobFunc, &jobParameters );
}
for ( Int32 i = 0; i < JOB_COUNT; ++i )
{
CThread & thread = CThreads::threadArray[ i ];
// Prints 2 ms sometimes whith i = 0
thread.WaitUntilJobDone();
}
}
}
两件事:
您无条件地放弃了处理器时间,并且在某些旧版本的 windows 上,您放弃了整个进程,而不仅仅是线程:
std::this_thread::sleep_for( std::chrono::nanoseconds(0) );
这个 yield 是不必要的。我怀疑你这样做的原因是没有它你会得到一个自旋循环,这是因为你正在读取和写入单个条件变量。
您需要两个条件变量,一个用于未完成的工作,一个用于完成的工作。通常,侦听器会将条件变量或包含它的结构作为参数传递给线程函数,从而允许您从调度程序传递单个条件变量。