2016-11-18 51 views
1

我不明白爲什麼當「封裝」到類中時,pthread只使用一個線程,而在使用普通調用pthread函數時使用所有線程。實施中應該出現錯誤。Pthread在封裝到類中時只使用一個線程

參見以下代碼:

#include <iostream> 
#include <vector> 
#include <pthread.h> 
#include <sys/time.h> 


namespace { 
    class Functor { 
    public: 
    Functor(const std::vector<int> &v) : 
     m_v(v), m_res() { 
    } 

    Functor() : m_v(), m_res() { 
    } 

    void operator()() { 
     computeImpl(); 
    } 

    std::vector<int> getResult() const { 
     return m_res; 
    } 

    private: 
    std::vector<int> m_v; 
    std::vector<int> m_res; 

    void computeImpl() { 
     //Long computation (remove duplicates) 
     for (size_t i = 0; i < m_v.size(); i++) { 
     bool duplicate = false; 

     for (size_t j = 0; j < m_res.size() && !duplicate; j++) { 
      if (m_v[i] == m_res[j]) { 
      duplicate = true; 
      } 
     } 

     if (!duplicate) { 
      m_res.push_back(m_v[i]); 
     } 
     } 
    } 
    }; 

    void * thread(void * args) { 
    Functor* f = reinterpret_cast<Functor*>(args); 
    (*f)(); 
    return 0; 
    } 

    double measureTimeMs() { 
    struct timeval tp; 
    gettimeofday(&tp,0); 
    return(1000.0*tp.tv_sec + tp.tv_usec/1000.0); 
    } 

    class MyThread { 
    public: 
    MyThread(void * (*func)(void *), void *arg) : m_pid() { 
     pthread_create(&m_pid, NULL, func, arg); 
    } 

    MyThread() : m_pid() { } 

    virtual ~MyThread() { 
     join(); 
    } 

    void join() { 
     pthread_join(m_pid, NULL); 
    } 

    private: 
    pthread_t m_pid; 
    }; 
} 

int main() { 
    //Pthread encapsulated into a class 
    size_t nb_threads = 4; 
    std::vector<MyThread> threads(nb_threads); 
    std::vector<Functor> functors(nb_threads); 

    std::vector<int> v(100000); 
    srand(0); 
    for (size_t i = 0; i < v.size(); i++) { 
    v[i] = rand(); 
    } 

    double t_thread = measureTimeMs(); 
    for (size_t i = 0; i < nb_threads; i++) { 
    functors[i] = Functor(v); 
    threads[i] = MyThread(thread, &functors[i]); 
    } 

    for (size_t i = 0; i < nb_threads; i++) { 
    threads[i].join(); 
    } 
    t_thread = measureTimeMs() - t_thread; 
    std::cout << "Pthread encapsulated into a classs" << std::endl; 
    std::cout << "t_thread=" << t_thread << " ms" << std::endl; 


    //Only Pthread 
    std::vector<pthread_t> pid(nb_threads); 
    t_thread = measureTimeMs(); 
    for (size_t i = 0; i < nb_threads; i++) { 
    functors[i] = Functor(v); 
    pthread_create(&pid[i], NULL, thread, &functors[i]); 
    } 

    for (size_t i = 0; i < nb_threads; i++) { 
    pthread_join(pid[i], NULL); 
    } 
    t_thread = measureTimeMs() - t_thread; 
    std::cout << "Only Pthread" << std::endl; 
    std::cout << "t_thread=" << t_thread << " ms" << std::endl; 

    return EXIT_SUCCESS; 
} 

輸出:

Pthread的封裝到班組長

t_thread = 4056.75毫秒

只有Pthread的

t_thread = 2619.55 ms

我的環境:Ubuntu 16.04和我使用系統監視器來檢查CPU活動。在第一種情況(封裝)中,只有一個線程處於100%,而在第二種情況下它使用4個線程,100%。

此外,我的電腦有2個核心/ 4線程。

+0

簡化您的代碼。有一件事你不需要所有這種C風格的轉換到'(size_t)'。首先使用'size_t'變量。然後,使用調試器或'cout'。 –

回答

1

您的線程設置正在引入副本。此外,這些副本的來源在創建線程時同步銷燬(因此在下一個線程啓動之前啓動,運行和連接等)。並且將最終的鹽加入傷口中,加入也是兩次。

更改設置:

std::vector<MyThread> threads; 
std::vector<Functor> functors; 

threads.reserve(nb_threads); 
functors.reserve(nb_threads); 

for (int i = 0; i < nb_threads; i++) 
{ 
    functors.emplace_back(v); 
    threads.emplace_back(thread, &functors[(size_t) i]); 
} 

// will fire all destructors, and consequently join. 
threads.clear(); 

注意我們這裏不火join方法。你的析構函數已經這樣做了,並且當線程向量爲clear() -ed時將被解僱。進一步。我們爲線程保留空間,並在矢量中就地構建它們。

運行上述應該會讓你找到你想要的數字相似性。

+0

謝謝,它解決了我的問題。這部分代碼來自庫,如何修改實現以便能夠在沒有C++ 11和'emplace_back'的情況下使用編譯器? – Catree

+0

@Catree相當繁瑣(不是C++ 11,後來纔是盛大的?)。這需要建立一個「啓動」機制,以便在線程就位之後啓動線程,而不是在構建時啓動線程。我們距離C++ 11的最終規範差不多6年了,現在每個知名供應商都有它(甚至是MS),所以要衡量它是否值得追求。 – WhozCraig

+0

你對C++ 11的支持是正確的。將與lib維護者交談,以考慮更多的C++ 11代碼。我使用了一個指向'MyThread'的指針來避免複製問題。多次調用'pthread_join'是否安全?否則,可能使用一個標誌來避免在析構函數中再次調用join()。 – Catree