2017-06-06 63 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