Understanding locking in linked lists

I am learning right now about locks with mutex and about multi threaded data structures. I am trying to implement a concurrent sorted linked list data structure that supports insertion,deletion,printing and freeing the entire list and I have written all the functions.Unfortunately for me I am fairly new to the concept of locks within threads. I tried implementing the sorted linked list with hand-over-hand locking but the insertion and the removal of elements are not working (I tried the functions on a Red Hat VM) and I do not know if the print function is right either.I have a problem with debugging with Linux because I am fairly new to it. Any suggestion on correcting my code bellow ? Note that I am looking for an explanation on how to implement the hand over hand locking in the best way possible and not for an entire code as an answer. Thanks in advance.

concurrent_list.h :

a header file for functions and structs declarations.

 typedef struct node node;   typedef struct list list;    list* create_list();   void delete_list(list* list);   void print_list(list* list);   void insert_value(list* list, int value);   void remove_value(list* list, int value);   void count_list(list* list, int (*predicate)(int)); 

concurrent_list.c

The file which the implementation of the functions in the header file and also more functions.

#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include "concurrent_list.h"  struct node {   int value;   node* next;   pthread_mutex_t lock; // hand over hand implies a lock for every node };  struct list {   node* head; };  // print the value of a node void print_node(node* node) {   if(node)   {     printf("%d ", node->value);   } }  // create  a new empty list list* create_list() {   list* new_list = (list*)malloc(sizeof(list));    if(new_list == NULL)   {     return NULL;   }    new_list->head = NULL;    return new_list; }  // delete the entire list (lock the current element for other threads) void delete_list(list* list) {   node* temp = list->head;   node* curr;    if(temp == NULL) return;     while (temp != NULL)    {        pthread_mutex_lock(&(temp->lock));        curr = temp;        free(curr);        temp = temp->next;     } }  // insert function for a new value if a value already exists then do nothing // lock the current and previous elements for other threads void insert_value(list* list, int value) {     if(list == NULL) return;      node* new_node = (node*)malloc(sizeof(node));      if(new_node == NULL) return;      new_node->value = value;      if(list->head == NULL)     {         list->head = new_node;         list->head->next = NULL;     }      node* prev = list->head;     pthread_mutex_lock(&prev->lock);      node* curr = prev->next;      if(curr == NULL)     {         if(prev->value > value)         {             new_node->next = prev;             prev->next == NULL;         }          else if(prev->value < value)         {             prev->next = new_node;             new_node->next = NULL;         }          else         {             free(new_node);         }          pthread_mutex_unlock(&prev->lock);          return;     }      pthread_mutex_lock(&curr->lock);      while(curr->value < value)     {       pthread_mutex_unlock(&prev->lock);       prev = curr;       curr = prev->next;        if(curr == NULL)       {         pthread_mutex_unlock(&prev->lock);         return;       }        pthread_mutex_lock(&curr->lock);     }      if(curr->value == value)     {        pthread_mutex_unlock(&curr->lock);        pthread_mutex_unlock(&prev->lock);        return;     }      new_node->next = curr;     prev->next = new_node;     pthread_mutex_unlock(&curr->lock);     pthread_mutex_unlock(&prev->lock); }  //delete the first appearance of a value in the list if it exists in the list // lock the current and previous elements for other threads void remove_value(list* list, int value) {     if(list == NULL || list->head == NULL) return;      node* prev = list->head;     pthread_mutex_lock(&prev->lock);      node* curr = prev->next;      if(curr == NULL)     {         if(prev->value == value)         {             prev->next == NULL;         }          pthread_mutex_unlock(&prev->lock);          return;     }      pthread_mutex_lock(&curr->lock);      while(curr->value < value)     {       pthread_mutex_unlock(&prev->lock);       prev = curr;       curr = prev->next;        if(curr == NULL)       {         pthread_mutex_unlock(&prev->lock);         return;       }        pthread_mutex_lock(&curr->lock);     }      if(curr->value == value)     {         prev->next = curr->next;     }     pthread_mutex_unlock(&curr->lock);     pthread_mutex_unlock(&prev->lock); }  //print the entire list // lock the current element for other threads void print_list(list* list) {   node* curr = list->head;    while(curr != NULL)   {       pthread_mutex_lock(&curr->lock);       print_node(curr);       pthread_mutex_unlock(&curr->lock);       curr = curr->next;   }   printf("\n"); }  // print how many nodes in the list satisfy a given predicate function // lock the current element for other threads void count_list(list* list, int (*predicate)(int)) {   int count = 0;   node* curr = list->head;    while(curr != NULL)   {       pthread_mutex_lock(&curr->lock);        if(predicate(curr->value))       {           count++;       }        pthread_mutex_unlock(&curr->lock);        curr = curr->next;   }    printf("%d items were counted\n", count); } ```