2011-11-19 48 views
0

我寫了一個程序,採用多線程進行並行計算。我已經證實,在我的系統(OS X)上它同時最大化了兩個內核。我只是將它移植到Ubuntu上,不需要任何修改,因爲我在考慮該平臺的情況下對其進行了編碼。特別是,我在Amazon EC2上運行Canonical HVM Oneiric映像,這是一個集羣計算4x大型實例。這些機器配備2個Intel Xeon X5570四核CPU。C++ pthread多線程處理2個Intel Xeon X5570,四核CPU上Amazan EC2 HPC ubuntu實例

不幸的是,我的程序沒有在EC2機器上完成多線程。運行多個線程實際上會減慢每個附加線程的運算速度。在我的程序運行時運行頂部顯示,當多於一個線程被初始化時,CPU消耗的系統%大致與線程數成比例。只有1個線程,%sy是〜0.1。無論哪種情況,用戶%都不會超過〜9%。

下面是我的代碼

const int NUM_THREADS = N; //where changing N is how I set the # of threads 

void Threading::Setup_Threading() 
{ 
    sem_unlink("producer_gate"); 
    sem_unlink("consumer_gate"); 
    producer_gate = sem_open("producer_gate", O_CREAT, 0700, 0);   
    consumer_gate = sem_open("consumer_gate", O_CREAT, 0700, 0); 
    completed = 0; 
    queued  = 0;    

    pthread_attr_init (&attr); 
    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 
} 

void Threading::Init_Threads(vector <NetClass> * p_Pop) 
{ 

    thread_list.assign(NUM_THREADS, pthread_t());   
    for(int q=0; q<NUM_THREADS; q++) 
     pthread_create(&thread_list[q], &attr, Consumer, (void*) p_Pop); 
} 

void* Consumer(void* argument) 
{ 

    std::vector <NetClass>* p_v_Pop = (std::vector <NetClass>*) argument ; 

    while(1) 
    { 
     sem_wait(consumer_gate); 
     pthread_mutex_lock (&access_queued); 
     int index = queued;       
     queued--; 
     pthread_mutex_unlock (&access_queued); 

     Run_Gen( (*p_v_Pop)[index-1]); 

     completed--; 
     if(!completed)     
      sem_post(producer_gate); 
    } 
} 

main() 
{ 
    ... 
    t1 = time(NULL); 
    threads.Init_Threads(p_Pop_m); 
    for(int w = 0; w < MONTC_NUM_TRIALS ; w++) 
    { 
     queued = MONTC_POP; 
     completed = MONTC_POP; 

     for(int q = MONTC_POP-1 ; q > -1; q--) 
      sem_post(consumer_gate); 

     sem_wait(producer_gate); 

    } 
    threads.Close_Threads(); 
    t2 = time(NULL); 
    cout << difftime(t2, t1); 
    ... 
} 
+0

也許會發生這種情況,因爲EC2核心是虛擬核心而不是真正的金屬固體核心 – fabrizioM

+0

您可以提供最少的來源,可以編譯? – fghj

+0

@ user1034749自從您發佈此嘗試隔離問題代碼以來,我花了數小時,並且我仍然有一種方法,直到我完全縮小它的範圍。我確定的是,它取決於'Consumer()'中調用的'工作'。我用一個虛擬函數替換了'Run_Gen',它只是循環浪費時間,然後線程按設計工作。 'Run_Gen'發生了很多事情(因此困難),但沒有一個是非常特殊的,只是向量和算術。對可能發生的事情有任何想法,至少在一般情況下。 –

回答

2

好線程相關的部分,只是猜測。有一種簡單的方法可以將並行代碼轉換爲連續代碼。例如:

thread_func: 
    while (1) { 
    pthread_mutex_lock(m1); 
    //do something 
    pthread_mutex_unlock(m1); 
    ... 
    pthread_mutex_lock(mN); 
    pthread_mutex_unlock(mN); 

如果您運行的幾個線程這樣的代碼,你將不會看到,因爲互斥使用的任何加速。代碼將連續工作,而不是平行。任何時候只有一個線程可以工作。

不好的事情,你不能在你的程序中使用任何互斥體,但仍然有這種情況。例如,「malloc」的調用可能會導致一些在「C」運行時使用互斥體,「write」調用可能導致在Linux內核某處使用互斥體。即使調用gettimeofday也會導致互斥鎖/解鎖(如果告訴Linux/glibc,它們會導致互斥)。

您可能只有一個互斥量,但花費了很多時間,這可能會導致此類行爲。

由於互斥鎖可能在內核和C/C++運行時的某個地方使用,因此可以在不同的操作系統中看到不同的行爲。

+0

Rand()可能會導致互斥量的使用嗎?因爲'Rand()'在'Run_Gen()'中被調用了很多次。或者'vector_name.push_back();','vector_name.assign();','vector_name(n);','vector_name [x]'?可能'exp();'從''。這些是在'Run_Gen'內調用的庫函數。除了'Consumer()'外,在我的代碼中沒有使用明確性,我認爲我們可以排除它。 –

+0

push_back當然可以,它使用一些內存分配器,如果capicity不夠。雖然通常每個核心有幾個內存池或類似的機制,但可能運行時不是最新的。您可以通過在程序中運行「strace」來檢查。然後在strace log中grep「futex」。 – fghj

+0

和linux上的rand使用mutex,你可以看看glibc的源代碼:glibc/stdlib/rand。c:rand-> return random(),while random:libc_lock_lock(lock); random_r(&unsafe_state,&retval); libc_lock_unlock(鎖定); – fghj