将作业发送到std :: thread

时间:2016-02-29 22:00:51

标签: multithreading c++11 mutex stdthread

我对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();
        }
     }
}

1 个答案:

答案 0 :(得分:0)

两件事:

您无条件地处理您的处理器时间,并且在某些旧版本的Windows上,您将产生整个过程,而不仅仅是线程:

std::this_thread::sleep_for( std::chrono::nanoseconds(0) );

这种收益是不必要的。我怀疑你这样做的原因是没有它你会得到一个旋转循环,这是因为你正在阅读和写入一个条件变量。

您需要两个条件变量,一个用于待处理工作,另一个用于完成工作。通常,侦听器会将条件变量或包含它的结构作为参数传递给线程函数,从而允许您从调度程序传递单个条件变量。