2016-02-29 51 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