2017-05-06 687 views
1

我有一個memcpy問題,我似乎並不明白。我在一個線程上使用memcpy,與我從主體運行時相比,速度降低了3-4倍。在這兩種情況下,我有2個線程運行一個只等待和一個調用memcpy。你能給我任何可能的解釋嗎?我使用超線程的4核英特爾機器。memcpy在線程中調用的速度很慢

#include <stdio.h> 
#include <unistd.h> 
#include <sys/time.h> 
#include <string.h> 
#include <pthread.h> 
#include <algorithm> 
#define MILLION 1000000 

#define START_TIMER(timer) {   \ 
    gettimeofday(&(timer), NULL);   \ 
} 

#define STOP_TIMER(timer) {   \ 
    gettimeofday(&(timer), NULL);   \ 
} 

#define TIME_DIFF(timer1, timer2, total) {  \ 
    long long sec_diff = 0;   \ 
    long long usec_diff = 0;   \ 
    sec_diff = (timer2).tv_sec - (timer1).tv_sec;  \ 
    usec_diff = (timer2).tv_usec - (timer1).tv_usec; \ 
    (total)+= (sec_diff * MILLION) + usec_diff;  \ 
} 
void copy(){ 
    struct timeval start, stop; 
    long long total=0; 
    char buff[1024*1024]; 
    for(int i =0;i<100;i++){ 

    char* temp = new char[1024*1024]; 
    START_TIMER(start); 
    std::copy(buff,buff+1024*1024,temp); 
    STOP_TIMER(stop); 
    TIME_DIFF(start,stop,total); 
    delete temp; 
    } 
    printf("%lld\n",total/100); 
} 
void* mem(void* args){ 
    copy(); 
    pthread_exit(NULL); 
} 

void * nothing(void *args){ 
    pthread_exit(NULL); 

} 
pthread_t thread; 
int main(int argc,char* argv[]){ 
    if(atoi(argv[1])==0){ 
     pthread_create(&thread,NULL,nothing,NULL); 
     pthread_join(thread,NULL); 
     copy(); 
    } 
    else{ 

     pthread_create(&thread,NULL,mem,NULL); 
     pthread_join(thread,NULL); 
    } 
} 

謝謝你的時間。我希望這不是太愚蠢。

+1

如果你在'i'循環之前初始化'buff',會發生什麼? – 1201ProgramAlarm

+0

請分享您從main和thread調用複製函數的代碼。這樣我們可以嘗試重現問題。 – Sush

+0

如果將main()中的copy()移動到線程創建之上,即先運行主線程副本,會發生什麼? – ThingyWotsit

回答

0

起初我不能讓你的代碼運行,當它調用copy()發生線程(傳遞1作爲參數)。 pthread_create分配一個小堆棧大小,並聲明1MB數組buff導致分段錯誤。

我改變了代碼分配較大的堆棧線程:

int main(int argc,char* argv[]){ 
    if(atoi(argv[1])==0){ 
     pthread_create(&thread,NULL,nothing,NULL); 
     pthread_join(thread,NULL); 
     copy(); 
    } 
    else{ 
     pthread_attr_t thread_attr; 
     pthread_attr_init(&thread_attr); 
     pthread_attr_setstacksize(&thread_attr , 20*1024*1024); 
     pthread_create(&thread, &thread_attr,mem,NULL); 
     pthread_join(thread,NULL); 
    } 
} 

這工作,並有我的機器上或者線程在複製之間運行時沒有區別。

但是,您的操作系統可能會導致堆爭用。每次需要分配內存時,都需要控制'互斥量'(某種類型,可能是spin_lock),以確保沒有其他線程正在從堆中分配/釋放。這會導致你正在經歷的延遲。

+1

該代碼適用於我,因爲它是我的,並且我獲得了大約100個usecs和300個usecs。我也試過你的代碼,但我仍然有同樣的問題。感謝您的時間,我很感激。我剛剛看到你的操作系統和堆上的互斥體的編輯。這不應該爲這兩種情況造成問題嗎?爲什麼它只能在其中一個上顯而易見 – Pol

+0

您是否閱讀了關於堆爭用的更新?我認爲我們的架構以不同的方式處理堆。 –

+0

(我與四個核心和超線程的I7運行,操作系統是否爲Mac OS 10.11 BTW) –

0

似乎是在「複製」函數被調用該進程的線程數的差異。當它從主線程調用時,'Nothing'線程已經退出,所以實際上只有一個進程線程。但是,當從'mem'線程調用時,系統中實際上有兩個線程。如果系統被加載或進程的線程之間存在爭用,這可能會有所不同。如果它在另一臺機器上運行,或者在較少加載的機器上運行,則此時間差可能不存在。可以通過更改代碼來驗證此理論,以便在無線程中等待並僅在調用複製函數後才取消它。

+0

您是對的,副本應在加入之前。我解決了這個問題,但我仍然有同樣的結果。感謝您的糾正。 – Pol