2017-06-06 55 views
0

我有簡單的C++代碼,它首先創建4個線程,然後將1000次數字1發送到C++隊列,然後是4個0.每個線程試圖從該隊列讀取,並且當任何線程讀取0時,它終止並打印其局部總和。如果它讀取1,那麼它只會將總和加1。讀數用互斥鎖保護。代碼按照預期在5次中的4次中有效,但有時會得到double free or corruption (!prev) error... ...Abort core dumped。我也使用gdb調試了代碼,但只得到了received signal SIGABRT, Aborted ... ...at raise.c: No such file or directory".我沒有明確分配或釋放任何內存。什麼可能導致這個問題?使用線程和互斥鎖時出現雙重空閒或損壞(!prev)錯誤

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <queue> 

std::queue<int> my_queue; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

void *process(void *arg){ 
    int sum = 0; 
    while(1){ 
     if(!my_queue.empty()){ 
      pthread_mutex_lock(&mutex); 
      if (my_queue.front() == 1){ 
       sum += 1; 
       my_queue.pop(); 
       pthread_mutex_unlock(&mutex); 
      } 
      else{ 
       my_queue.pop(); 
       printf("Sum: %d\n", sum); 
       pthread_mutex_unlock(&mutex); 
       break; 
      } 
     } 
    } 
    return arg; 
} 

int main(void){ 
    pthread_t id[4]; 
    for(int i = 0; i < 4; i++){ 
     if (pthread_create(&id[i], NULL, process, NULL) != 0){ 
      fprintf(stderr, "%s\n", "Error creating thread!"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    for (int i = 0; i < 1000; i++){ 
     my_queue.push(1); 
    } 
    for (int i = 0; i < 4; i++){ 
     my_queue.push(0); 
    } 
    for (int i = 0; i < 4; i++){ 
     pthread_join(id[i], NULL); 
    } 
    return EXIT_SUCCESS; 
} 
+2

'if(!my_queue.empty()){' - 不在鎖內,TOCTTOU錯誤。 – ThingyWotsit

+2

那麼你在沒有保護的情況下會大量推入'my_queue'。 –

+0

通常使用至少一個信號量來計數隊列中的條目,從而防止在空隊列上循環。 – ThingyWotsit

回答

0

你有兩個問題:

首先你是推到隊列,並且不持有鎖,其次要測試如果隊列不持有鎖空。

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <queue> 

std::queue<int> my_queue; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

void *process(void *arg){ 
    int sum = 0; 
    bool keep_going = true; 
    while(keep_going){ 
     pthread_mutex_lock(&mutex); 
     if(!my_queue.empty()){ 
      if (my_queue.front() == 1){ 
       sum += 1; 
      } 
      else{ 
       keep_going=false; 
      } 
     } 
     my_queue.pop(); 
     pthread_mutex_unlock(&mutex); 
    } 
    printf("Sum: %d\n", sum); // Don't do IO while holding a lock! 
    return arg; 
} 

int main(void){ 
    pthread_t id[4]; 
    // Initialize queue *before* creating threads. 
    for (int i = 0; i < 1000; i++){ 
     my_queue.push(1); 
    } 
    for (int i = 0; i < 4; i++){ 
     my_queue.push(0); 
    } 
    // Create threads 
    for(int i = 0; i < 4; i++){ 
     if (pthread_create(&id[i], NULL, process, NULL) != 0){ 
      fprintf(stderr, "%s\n", "Error creating thread!"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    // Join them. 
    for (int i = 0; i < 4; i++){ 
     pthread_join(id[i], NULL); 
    } 
    return EXIT_SUCCESS; 
} 

如果你想創建線程後添加到隊列中,你需要的東西,如:

pthread_mutex_lock(&mutex); 
    my_queue.push(value); 
    pthread_mutex_unlock(&mutex); 

裏面的for循環。此外,在到達零點之前,有一個真正的隊列清空機會。無論是做由等待信號燈正常,或隊列循環需要變得像:

 pthread_mutex_lock(&mutex); 
     if(my_queue.empty()){ 
      pthread_mutex_unlock(&mutex); 
      usleep(1); 
      pthread_mutex_lock(&mutex); 
     } else { 

當線程將短暫睡眠,讓隊列填滿。

此外,你正在用C++編寫。學習編寫RAII類來調用pthread_mutex_lock並解鎖。

+0

謝謝!我明白了,但是,假設我想先創建線程,然後像在我的例子中那樣初始化隊列,然後如何通過互斥鎖保護添加元素到隊列中? – Chilcone

相關問題