2016-06-21 1 views
0

이것은 valgrind의 memcheck의 출력을 보여주고 검토하는 데 도움이되는 약간의 테스트입니다. 누군가 나를 제거하고 목록의 중간에서 노드를 해제하는 방법을 알아낼 수 있습니까? remove 노드 섹션에서 free (cur) 및 free (cur-> lock)를 주석 처리하면 memcheck가 메모리 누수가 있다고 알려주지 만, 그 노드를 유지하면 맨 위의 잘못된 읽기를 수행하고 있습니다. 루프. 이 수수께끼에서 벗어날 길이 있습니까?valgrind 오류없이 목록의 중간에 삭제 된 노드를 해제하는 방법은 무엇입니까?

TEST(UtilityGeneralUnittest, valgrindTests) 
{ 
    //declare a node type 
    typedef struct node{ 
     int size; 
     int value; 
     struct node *next; 
     pthread_mutex_t *lock; 
    }node_t; 

    //make the head 
    node_t *head; 
    head = (node_t*)malloc(1 * sizeof(node_t)); 
    head->size = 0; 
    head->next = NULL; 
    head->lock = (pthread_mutex_t*)malloc(1 * sizeof(pthread_mutex_t)); 
    pthread_mutex_init(head->lock, NULL); 

    //create array for storing values 
    int array[10]; 


    //build a list with random numbers 
    for (int i = 0; i < 10; i++) 
    { 
     node_t *newNode; 
     newNode = (node_t*)malloc(1 * sizeof(node_t)); 
     newNode->value = rand() % 100 + 1; 
     newNode->next = NULL; 
     newNode->lock = (pthread_mutex_t*) malloc(1 * sizeof(pthread_mutex_t)); 
     pthread_mutex_init(newNode->lock, NULL); 
     array[i] = newNode->value; 
     if (head->next == NULL) 
     { 
      head->next = newNode; 
      head->size++; 
     } 
     else 
     { 
      node_t *tmp = head->next; 
      head->next = newNode; 
      newNode->next = tmp; 
      head->size++; 
     } 
    } 
    // assert the list added nodes 
    ASSERT_EQ(10, head->size); 

    //sanity check; print the list 
    node_t *printer = head; 
    while(printer->next != NULL) 
    { 
     printer = printer->next; 
     std::cout << "value: "; 
     std::cout << printer->value << ", "; 
    } 
    std::cout << "\n"; 
    // the meat and potatoes: deleting with locks. 
    int removeMe = array[rand() % 10]; 
    bool verifyDel = true; 
    int checkVal = removeMe; 
    node_t *prev; 
    node_t *cur; 

    prev = head; 
    pthread_mutex_lock(prev->lock); 
    while((cur = prev->next) != NULL) //******** this is the problem 
    { 
     pthread_mutex_lock(cur->lock); 
     if(cur->value == removeMe) 
     { 
      prev->next = cur->next; 
      pthread_mutex_unlock(cur->lock); 
      pthread_mutex_unlock(prev->lock); 
      cur->next = NULL; 
      head->size--; 
      free(cur->lock); ///******** this is the problem 
      free(cur); ///****** this is the problem 
     } 
     pthread_mutex_unlock(prev->lock); 
     prev = cur; 
    } 
    //pthread_mutex_unlock(prev->lock); 


    //verify node has been removed 
    printer = head; 
    while(printer->next != NULL) 
    { 
     printer = printer->next; 
     if(printer->value == checkVal) 
     { 
      verifyDel = false; 
     } 
     std::cout << "value: "; 
     std::cout << printer->value << ", "; 
    } 
    std::cout << "\n"; 
    ASSERT_TRUE(verifyDel); 

    //clean up: delete the list 
    while((printer = head) != NULL) 
    { 
     head = head->next; 
     free(printer->lock); 
     free(printer); 
     std::cout << "free!!!" << std::endl; 
    } 


} 
+0

그리고 당신은 당신이 그들을 잠금보다 당신의 뮤텍스 번 잠금을 해제하는 것 ... –

+0

그것에 대해 죄송합니다 @TobySpeight , 네, 이것은 gTest 테스트 케이스입니다. 나는 당신이 함수의 고기를 main()으로 복사하고 지나쳐서 컴파일하고 실행할 수 있다고 상상할 것이다. malloc()을 사용하는 것은 C 프로그래머가 열심히 죽어가는 날입니다. :) 나는 당신의 제안을 시험해보고 그 과제를 테스트 해 볼 것입니다. 너 알려줘! –

+0

@TobySpeight 당신이 바로 그 임무였습니다. 과제를 둘러싼 테스트 케이스를 추가하는 대신 내 대답을 계속 읽습니다. –

답변

1

(간체) 루프에서 상대 :

while ((cur = prev->next) != NULL) //* problem 
{ 
    if (cur->value == removeMe) 
    { 
     prev->next = cur->next; 
     cur->next = NULL; 
     free(cur);    //* problem 
    } 
    prev = cur; 
} 

문제하면 할당 prev = cur으로하지만 if 블록이 평가되는 경우에만 사용할 수 있습니다. 그것은 cur을 해방 시켰고, 다음에 루프 주위에, cur=prev->next은 삭제 된 저장소를 참조합니다.

당신은 else을 삽입하여 cur가 제거되지 않은 경우에만 prev을 할당 할 것을 해결할 수 :

while ((cur = prev->next)) { 
    if (cur->value == removeMe) { 
     prev->next = cur->next; 
     cur->next = NULL; 
     free(cur); 
    } else { 
     prev = cur; 
    } 
} 
관련 문제