2016-02-29 72 views
0

我对std :: thread很新,我很快意识到创建它们至少在运行W7的计算机上是相当昂贵的。 所以我决定创建我的线程和使用样例代码为作业发送到它:http://en.cppreference.com/w/cpp/thread/condition_variable发送作业到一个std ::线程

我的代码运行良好,没有崩溃,但是我没有看到太多的性能提升,所以我测量的时间的工作之间的差异完成和主线程完成检测工作的时间(请参阅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(); 
     } 
    } 
} 

回答

0

两件事情:

你产生你的处理器时间无条件地,和一些旧版本的Windows,你产生的全过程,而不仅仅是线程:

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

该产量是不必要的。我怀疑你做这件事的原因是没有它你得到了一个旋转循环,这是因为你正在读写一个条件变量。

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

+0

感谢您的回答。一旦我有时间尝试,我会尽快回复您。 – OeilDeLance

+0

好吧,显然我的2毫秒来自我自己的错误。现在我已经将时间最多减少到了0.2毫秒。这是很多。 我也删除了产量,但它并没有改变一件事。 – OeilDeLance

+0

我不知道我明白为什么我需要两个条件变量。这个例子实现它只有一个等待两个不同的布尔:http://en.cppreference.com/w/cpp/thread/condition_variable。 我想如果它是一个布尔,它不会有任何区别。 – OeilDeLance