Thread: How to access a linked list structure from multiple threads

  1. #1
    Registered User
    Join Date
    Jul 2020
    Posts
    47

    How to access a linked list structure from multiple threads

    Hello,

    The aim is to add records to a linked list, from a function that runs that perpetually in a separate thread and have the contents of the linked_list accessible from multiple threads - rather than just the add_records thread.

    Consider the following code;


    • this code does not have a linked list
    • but the code is able to pass values (via a global structure) between two threads
    • this code works
    • and has formed the basis of my approach with the linked list version below which unfortunately doesn't work

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    struct arg_struct
    {
        int arg1;
        int arg2;
    } *args;
    
    void *print_the_arguments(void *arguments)
    {
        struct arg_struct *args = arguments;
        printf("Thread before\n");
        printf("%d\n", args->arg1);
        printf("%d\n", args->arg2);
        printf("\n");
    
        args->arg1 = args->arg1 + 10;
        args->arg2 = args->arg2 + 10;
    
        printf("Thread after\n");
        printf("%d\n", args->arg1);
        printf("%d\n", args->arg2);
        printf("\n");
    
        pthread_exit(NULL);
        return NULL;
    }
    
    int main()
    {
        pthread_t some_thread;
        args = malloc(sizeof(struct arg_struct) * 1);
    
        args->arg1 = 5;
        args->arg2 = 7;
    
        printf("Before\n");
        printf("%d\n", args->arg1);
        printf("%d\n", args->arg2);
        printf("\n");
    
        if (pthread_create(&some_thread, NULL, &print_the_arguments, args) != 0)
        {
            printf("print_the_arguments thread failed!\n");
            return -1;
        }
    
        pthread_join(some_thread, NULL); // Wait until thread is finished
    
        printf("After\n");
        printf("%d\n", args->arg1);
        printf("%d\n", args->arg2);
        printf("\n");
    
        return 0;
    }
    Consider the following the code;


    • this code executes the add_records function in a separate thread
    • the add_records function then add records to the linked list
    • in this example the add_records function also reports the contents of the linked list to demonstrate that the code to populate the linked list does work
    • this code doesn't accomplish my objective however, which is to add records to the linked_list in a separate thread; but then also access the linked_list from another thread (e.g. main)

    Code:
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <unistd.h>             // sleep
    #include <pthread.h>
    #include <time.h>
    
    #define FALSE 0
    
    struct record
    {
        int arg1;
        int arg2;
    };
    typedef struct record record_t;
    
    struct linked_list
    {
        struct record           *record;
        struct linked_list      *prev;
        struct linked_list      *next;
    };
    typedef struct linked_list linked_list_t;
    
    linked_list_t *add_at(int pos, linked_list_t *linked_list, record_t *record)
    {
        linked_list_t *node = malloc(sizeof(linked_list_t) * 1);
        if (node == NULL)
        {
            printf("Malloc failed in node: add_at\n");
            getchar();
        }
        node->record = malloc(sizeof(record_t) * 1);
        if (node->record == NULL)
        {
            printf("Malloc failed in: add_at: node->record\n");
            getchar();
        }
    
        node->record->arg1 = record->arg1;
        node->record->arg2 = record->arg2;
        node->prev = NULL;
        node->next = NULL;
    
        // handle case where linked_list is empty
        if (linked_list == NULL)
        {
            linked_list = node;
            return linked_list;
        }
    
        int idx = 0;
    
        linked_list_t *prev = NULL;
        linked_list_t *cur = linked_list;
    
        // walk through linked_list until pos or end is reached
        while (cur != NULL && idx != pos)
        {
            ++idx;
            prev = cur;
            cur = cur->next;
        }
    
        // insertion point reached
    
        // beginning, includes linked_list update
        if (idx == 0)
        {
            linked_list = node;
            node->next = cur;
            cur->prev = node;
            return linked_list;
        }
    
        // end
        if (cur == NULL)
        {
            prev->next = node;
            node->prev = prev;
            return linked_list;
        }
    
        // middle
        prev->next = node;
        node->prev = prev;
        node->next = cur;
        cur->prev = node;
        return linked_list;
    
    } // add_at
    
    linked_list_t *add_beg(linked_list_t *linked_list, record_t *record)
    {
        linked_list = add_at(0, linked_list, record);
        return linked_list;
    }  // add_beg
    
    void dump_fwd(linked_list_t *linked_list)
    {
        printf("Forward:\n");
        printf("--------\n");
    
        while (linked_list != NULL)
        {
            printf("Arg1: %d\n", linked_list->record->arg1);
            printf("Arg2: %d\n", linked_list->record->arg2);
            printf("\n");
            linked_list = linked_list->next;
        }
    } // dump_fwd
    
    void *add_records(void *arguments)
    {
        // Initialise linked_list
        linked_list_t *linked_list = malloc(sizeof(linked_list_t) * 1);
        if (linked_list == NULL)
        {
            printf("Malloc failed in: linked_list\n");
            getchar();
        }
    
        linked_list = NULL;
    
        // Initialise record
        record_t *record = malloc(sizeof(record_t) * 1);
        if (record == NULL)
        {
            printf("Malloc failed in: record\n");
            getchar();
        }
    
        // Create record
        record->arg1 = 10;
        record->arg2 = 15;
    
        // Add record to linked_list
        linked_list = add_beg(linked_list,record);
    
        // Display linked_list
        dump_fwd(linked_list);
    
        // Create record
        record->arg1 = 20;
        record->arg2 = 25;
    
        // Add record to linked_list
        linked_list = add_beg(linked_list,record);
    
        // Display linked_list
        dump_fwd(linked_list);
    
        pthread_exit(NULL);
        return NULL;
    
    } // add_records
    
    int main()
    {
        pthread_t tid_add_records;
    
        if (pthread_create(&tid_add_records, NULL, &add_records, NULL) != 0)
        {
            printf("add_records thread failed!\n");
            return -1;
        }
    
        // Wait until thread is finished
        pthread_join(tid_add_records, NULL);
    
        return 0;
    }
    Consider the following code;


    • this is an attempt to combine the first two examples
    • separate thread to execute the add_records function
    • display the contents of the linked_list from main to demonstrate that the linked_list is accessible from multiple threads
    • however the calls to dump_fwd(linked_list) in main do not report any details. So there is a problem with the logic somewhere.
    • like the previous example, I call dump_fwd_II(linked_list) from within add_records to confirm that the linked_list is being updated within the add_records function. But it is as if the linked_list is a local variable

    Code:
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <unistd.h>             // sleep
    #include <pthread.h>
    #include <time.h>
    
    #define FALSE 0
    
    struct record
    {
        int arg1;
        int arg2;
    };
    typedef struct record record_t;
    
    struct linked_list
    {
        struct record           *record;
        struct linked_list      *prev;
        struct linked_list      *next;
    } *add_records_args;
    typedef struct linked_list linked_list_t;
    
    linked_list_t *add_at(int pos, linked_list_t *linked_list, record_t *record)
    {
        linked_list_t *node = malloc(sizeof(linked_list_t) * 1);
        if (node == NULL)
        {
            printf("Malloc failed in node: add_at\n");
            getchar();
        }
        node->record = malloc(sizeof(record_t) * 1);
        if (node->record == NULL)
        {
            printf("Malloc failed in: add_at: node->record\n");
            getchar();
        }
    
        node->record->arg1 = record->arg1;
        node->record->arg2 = record->arg2;
        node->prev = NULL;
        node->next = NULL;
    
        // handle case where linked_list is empty
        if (linked_list == NULL)
        {
            linked_list = node;
            return linked_list;
        }
    
        int idx = 0;
    
        linked_list_t *prev = NULL;
        linked_list_t *cur = linked_list;
    
        // walk through linked_list until pos or end is reached
        while (cur != NULL && idx != pos)
        {
            ++idx;
            prev = cur;
            cur = cur->next;
        }
    
        // insertion point reached
    
        // beginning, includes linked_list update
        if (idx == 0)
        {
            linked_list = node;
            node->next = cur;
            cur->prev = node;
            return linked_list;
        }
    
        // end
        if (cur == NULL)
        {
            prev->next = node;
            node->prev = prev;
            return linked_list;
        }
    
        // middle
        prev->next = node;
        node->prev = prev;
        node->next = cur;
        cur->prev = node;
        return linked_list;
    
    } // add_at
    
    linked_list_t *add_beg(linked_list_t *linked_list, record_t *record)
    {
        linked_list = add_at(0, linked_list, record);
        return linked_list;
    }  // add_beg
    
    void dump_fwd(linked_list_t *linked_list)
    {
        printf("Forward:\n");
        printf("--------\n");
    
        while (linked_list != NULL)
        {
            printf("Arg1: %d\n", linked_list->record->arg1);
            printf("Arg2: %d\n", linked_list->record->arg2);
            printf("\n");
            linked_list = linked_list->next;
        }
    } // dump_fwd
    
    void dump_fwd_II(linked_list_t *linked_list)
    {
        printf("Forward from within thread:\n");
        printf("---------------------------\n");
    
        while (linked_list != NULL)
        {
            printf("Arg1: %d\n", linked_list->record->arg1);
            printf("Arg2: %d\n", linked_list->record->arg2);
            printf("\n");
            linked_list = linked_list->next;
        }
    } // dump_fwd_II
    
    void *add_records(void *arguments)
    {
        struct linked_list *linked_list = arguments;
    
        // Initialise record
        record_t *record = malloc(sizeof(record_t) * 1);
        if (record == NULL)
        {
            printf("Malloc failed in: record\n");
            getchar();
        }
    
        // Create record
        record->arg1 = 10;
        record->arg2 = 15;
    
        // Add record to linked_list
        linked_list = add_beg(linked_list,record);
    
        // Display linked_list
        dump_fwd_II(linked_list);
    
        sleep(5);
    
        // Create record
        record->arg1 = 20;
        record->arg2 = 25;
    
        // Add record to linked_list
        linked_list = add_beg(linked_list,record);
    
        // Display linked_list
        dump_fwd_II(linked_list);
    
        pthread_exit(NULL);
        return NULL;
    
    } // add_records
    
    int main()
    {
        int done;
        done = FALSE;
    
        pthread_t tid_add_records;
    
        // Initialise linked_list
        linked_list_t *linked_list = malloc(sizeof(linked_list_t) * 1);
        if (linked_list == NULL)
        {
            printf("Malloc failed in: linked_list\n");
            getchar();
        }
    
        linked_list = NULL;
    
        add_records_args = linked_list;
    
        if (pthread_create(&tid_add_records, NULL, &add_records, add_records_args) != 0)
        {
            printf("add_records thread failed!\n");
            return -1;
        }
    
        while (!done)
        {
            sleep(2);
    
            // Display linked_list
            dump_fwd(linked_list);
    
            sleep(8);
    
            // Display linked_list
            dump_fwd(linked_list);
    
            break;
        }
    
        // Wait until thread is finished
        pthread_join(tid_add_records, NULL);
    
        return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,736
    Try this.
    Code:
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <unistd.h>             // sleep
    #include <pthread.h>
    #include <time.h>
    
    #define FALSE 0
    #define TRUE 1
    
    typedef struct record
    {
      int arg1;
      int arg2;
    } record_t;
    
    // Step 1, separated the nodes (containing data) from the list header
    typedef struct node {
      record_t  record;
      struct node *next;
      struct node *prev;
    } node_t;
    
    // Step 2, give the header a mutex as well.
    typedef struct threaded_linked_list
    {
      pthread_mutex_t mutex;
      node_t          *head;
      node_t          *tail;
    } tll_t;
    
    // or use this in main
    // https://linux.die.net/man/3/pthread_tryjoin_np
    volatile int done = FALSE;
    
    void add_at(int pos, tll_t *list, record_t *record)
    {
      node_t *node = malloc(sizeof(*node));
      node->record = *record;
      node->next = NULL;
      node->prev = NULL;
    
      // Step 3.
      // Anything touching the list or it's contents
      // needs to be protected in multiple threaded environments.
      pthread_mutex_lock(&list->mutex);
    
      if ( list->head == NULL )
      {
        list->head = list->tail = node;
      }
      else
      {
        node_t  *cur = list->head;
        node_t  *prev = NULL;
        int idx = 0;
        // walk through linked_list until pos or end is reached
        while (cur != NULL && idx != pos)
        {
            ++idx;
            prev = cur;
            cur = cur->next;
        }
        // insertion point reached
    
        // beginning, includes linked_list update
        if (idx == 0)
        {
            list->head = node;
            node->next = cur;
            cur->prev = node;
        }
        else if (cur == NULL)      // end
        {
            prev->next = node;
            node->prev = prev;
        }
        else
        {
          // middle
          prev->next = node;
          node->prev = prev;
          node->next = cur;
          cur->prev = node;
        }
      }
    
      pthread_mutex_unlock(&list->mutex);
    } // add_at
    
    void add_beg(tll_t *list, record_t *record)
    {
        add_at(0, list, record);
    } // add_beg
    
    void dump_fwd(tll_t *list)
    {
        printf("Forward:\n");
        printf("--------\n");
    
        pthread_mutex_lock(&list->mutex);
    
        node_t  *curr = list->head;
        while (curr != NULL)
        {
            printf("Arg1: %d\n", curr->record.arg1);
            printf("Arg2: %d\n", curr->record.arg2);
            printf("\n");
            curr = curr->next;
        }
    
        pthread_mutex_unlock(&list->mutex);
    } // dump_fwd
    
    void dump_fwd_II(tll_t *list)
    {
        printf("Forward from within thread:\n");
        printf("---------------------------\n");
    
        pthread_mutex_lock(&list->mutex);
    
        node_t  *curr = list->head;
        while (curr != NULL)
        {
            printf("Arg1: %d\n", curr->record.arg1);
            printf("Arg2: %d\n", curr->record.arg2);
            printf("\n");
            curr = curr->next;
        }
    
        pthread_mutex_unlock(&list->mutex);
    } // dump_fwd_II
    
    void *add_records(void *arguments)
    {
        tll_t *list = arguments;
    
        // Initialise record
        record_t record;
    
        // Create record
        record.arg1 = 10;
        record.arg2 = 15;
    
        // Add record to linked_list
        add_beg(list,&record);
    
        // Display linked_list
        dump_fwd_II(list);
    
        sleep(5);
    
        // Create record
        record.arg1 = 20;
        record.arg2 = 25;
    
        // Add record to linked_list
        add_beg(list,&record);
    
        // Display linked_list
        dump_fwd_II(list);
    
        done = TRUE;
        pthread_exit(NULL);
        return NULL;
    
    } // add_records
    
    int main()
    {
        pthread_t tid_add_records;
        tll_t     list;
    
        pthread_mutex_init(&list.mutex,NULL);
        list.head = list.tail = NULL;
    
        if (pthread_create(&tid_add_records, NULL, &add_records, &list) != 0)
        {
            printf("add_records thread failed!\n");
            return -1;
        }
    
        while (!done)
        {
            sleep(2);
    
            // Display linked_list
            dump_fwd(&list);
    
            sleep(8);
    
            // Display linked_list
            dump_fwd(&list);
        }
    
        // Wait until thread is finished
        pthread_join(tid_add_records, NULL);
    
        // cleanup
        pthread_mutex_destroy(&list.mutex);
    
        return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jul 2020
    Posts
    47
    Hello Salem,

    Thanks for responding!

    I spent a fair bit of time trying to work this out before I posted here. Without your help this would be really heavy going.

    I have added a remove function, which I try to call at line 353
    At the moment I'm getting the following obscure error which I don't understand
    Code:
    main.c|353|error: incompatible types when assigning to type ‘tll_t’ from type ‘struct tll_t *’|
    By the way, I realise in the example below, that by the time I am calling the rem function; the add_record thread is no longer running so technically in this example I don't need the mutex. But eventually I plan to be removing records from the list while the add_records thread is still running. So the rem function needs to be "thread-safe".

    Here is the updated code:
    Code:
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <unistd.h>             // sleep
    #include <pthread.h>
    #include <time.h>
    
    #define FALSE 0
    #define TRUE 1
    
    typedef struct record
    {
      int arg1;
      int arg2;
    } record_t;
    
    // Step 1, separated the nodes (containing data) from the list header
    typedef struct node {
      record_t  record;
      struct node *next;
      struct node *prev;
    } node_t;
    
    // Step 2, give the header a mutex as well.
    typedef struct threaded_linked_list
    {
      pthread_mutex_t mutex;
      node_t          *head;
      node_t          *tail;
    } tll_t;
    
    // or use this in main
    // https://linux.die.net/man/3/pthread_tryjoin_np
    volatile int done = FALSE;
    
    void add_at(int pos, tll_t *list, record_t *record)
    {
      node_t *node = malloc(sizeof(*node));
      node->record = *record;
      node->next = NULL;
      node->prev = NULL;
    
      // Step 3.
      // Anything touching the list or it's contents
      // needs to be protected in multiple threaded environments.
      pthread_mutex_lock(&list->mutex);
    
      // add at beginning or pos other than end
      if ( pos != -1)
      {
        if ( list->head == NULL )
        {
            list->head = list->tail = node;
        }
        else
        {
            node_t  *cur = list->head;
            node_t  *prev = NULL;
            int idx = 0;
            // walk through linked_list until pos or end is reached
            while (cur != NULL && idx != pos)
            {
                ++idx;
                prev = cur;
                cur = cur->next;
            }
            // insertion point reached
    
            // beginning, includes linked_list update
            if (idx == 0)
            {
                list->head = node;
                node->next = cur;
                cur->prev = node;
            }
            else if (cur == NULL)      // end
            {
                prev->next = node;
                node->prev = prev;
            }
            else
            {
            // middle
            prev->next = node;
            node->prev = prev;
            node->next = cur;
            cur->prev = node;
            }
        }  // list->head <> null
      } // pos <> -1
    
      // add at end
      if ( pos == -1 )
      {
        if ( list->tail == NULL )
        {
            list->tail = list->head = node;
        }
        else
        {
            node_t  *cur = list->tail;
            node_t  *next = NULL;
    
            list->tail = node;
            node->prev = cur;
            cur->next = node;
        }
    
      } // pos == -1
    
      pthread_mutex_unlock(&list->mutex);
    } // add_at
    
    void add_beg(tll_t *list, record_t *record)
    {
        add_at(0, list, record);
    } // add_beg
    
    void add_end(tll_t *list, record_t *record)
    {
        add_at(-1, list, record);
    } // add_end
    
    void dump_fwd(tll_t *list)
    {
        printf("Forward:\n");
        printf("--------\n");
    
        pthread_mutex_lock(&list->mutex);
    
        node_t  *curr = list->head;
        while (curr != NULL)
        {
            printf("Arg1: %d\n", curr->record.arg1);
            printf("Arg2: %d\n", curr->record.arg2);
            printf("\n");
            curr = curr->next;
        }
        pthread_mutex_unlock(&list->mutex);
    } // dump_fwd
    
    void dump_rev(tll_t *list)
    {
        printf("Reverse:\n");
        printf("--------\n");
    
        pthread_mutex_lock(&list->mutex);
    
        node_t  *curr = list->tail;
        while (curr != NULL)
        {
            printf("Arg1: %d\n", curr->record.arg1);
            printf("Arg2: %d\n", curr->record.arg2);
            printf("\n");
            curr = curr->prev;
        }
        pthread_mutex_unlock(&list->mutex);
    } // dump_rev
    
    void dump_fwd_II(tll_t *list)
    {
        printf("Forward from within thread:\n");
        printf("---------------------------\n");
    
        pthread_mutex_lock(&list->mutex);
    
        node_t  *curr = list->head;
        while (curr != NULL)
        {
            printf("Arg1: %d\n", curr->record.arg1);
            printf("Arg2: %d\n", curr->record.arg2);
            printf("\n");
            curr = curr->next;
        }
        pthread_mutex_unlock(&list->mutex);
    } // dump_fwd_II
    
    tll_t *rem(tll_t *list, record_t *record)
    {
        pthread_mutex_lock(&list->mutex);
    
        node_t *curr = list->head;
    
        // walk through list
        while (curr != NULL)
        {
            // Found record
            if (
               (curr->record.arg1 == record->arg1) & \
               (curr->record.arg2 == record->arg2)
               )
            {
                // handle first item
                if (curr->prev == NULL)
                {
                    if (curr->next == NULL)
                    {
                        // only item?
                        list->head = NULL;
                    }
                    else
                    {
                        // more items?
                        list->head = curr->next;
                        list->head->prev = NULL;
                    }
                    free(curr);
                    pthread_mutex_unlock(&list->mutex);
                    return list;
                }
    
                // handle last item
                if (curr->next == NULL)
                {
                    curr->prev->next = NULL;
                    free(curr);
                    pthread_mutex_unlock(&list->mutex);
                    return list;
                }
    
                // handle middle item
                if (curr->prev != NULL && curr->next != NULL)
                {
                    curr->prev->next = curr->next;
                    curr->next->prev = curr->prev;
                    free(curr);
                    pthread_mutex_unlock(&list->mutex);
                    return list;
                }
            } // found record
    
    
            // Next record
            curr = curr->next;
    
        } // while (curr != NULL)
    
        // No match
        if (curr == NULL)
        {
            pthread_mutex_unlock(&list->mutex);
            return list;
        }
    
        pthread_mutex_unlock(&list->mutex);
        return list;
    
    } // rem
    
    void *add_records(void *arguments)
    {
        tll_t *list = arguments;
    
        // Initialise record
        record_t record;
    
        // Create record
        record.arg1 = 10;
        record.arg2 = 15;
    
        // Add record to linked_list
        add_end(list,&record);
    
        // Display linked_list
        // dump_fwd_II(list);
    
        sleep(5);
    
        // Create record
        record.arg1 = 20;
        record.arg2 = 25;
    
        // Add record to linked_list
        add_end(list,&record);
    
        sleep(5);
    
        // Create record
        record.arg1 = 30;
        record.arg2 = 35;
    
        // Add record to linked_list
        add_beg(list,&record);
    
        sleep(5);
    
        // Create record
        record.arg1 = 40;
        record.arg2 = 45;
    
        // Add record to linked_list
        add_beg(list,&record);
    
        // Display linked_list
        // dump_fwd_II(list);
    
        done = TRUE;
        pthread_exit(NULL);
        return NULL;
    
    } // add_records
    
    int main()
    {
        pthread_t tid_add_records;
        tll_t     list;
    
        pthread_mutex_init(&list.mutex,NULL);
        list.head = list.tail = NULL;
    
        if (pthread_create(&tid_add_records, NULL, &add_records, &list) != 0)
        {
            printf("add_records thread failed!\n");
            return -1;
        }
    
        while (!done)
        {
            sleep(2);
    
            // Display linked_list
            dump_fwd(&list);
    
            sleep(8);
    
            // Display linked_list
            dump_fwd(&list);
            dump_rev(&list);
        }
    
        // Wait until thread is finished
        pthread_join(tid_add_records, NULL);
    
        // Initialise record
        record_t record;
    
        // Create record
        record.arg1 = 10;
        record.arg2 = 15;
    
        // Delete record
        list = rem(&list,&record);
    
        dump_fwd(&list);
    
        // cleanup
        pthread_mutex_destroy(&list.mutex);
    
        return 0;
    }

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,736
    Study the add functions in more detail, especially why it's not necessary to return anything with this revised list structure.

    > (curr->record.arg1 == record->arg1) & \
    > (curr->record.arg2 == record->arg2)
    This should be &&, not &
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Jul 2020
    Posts
    47
    Hello Salem,

    Would you mind confirming that I'm using free correctly in the rem function.

    The rem function is working correctly in terms of the list pointers. That is, after removing a record. If I then list all the records, the list contents being displayed is as I expect.

    However, that really only means that the list pointers are being updated correctly. If I'm not using free correctly; besides running out of memory eventually, how can I check?

    Code:
    void rem(tll_t *list, record_t *record){
        pthread_mutex_lock(&list->mutex);
    
        node_t *curr = list->head;
    
        // walk through list
        while (curr != NULL)
        {
            // Found record
            if (
               (curr->record.arg1 == record->arg1) && \
               (curr->record.arg2 == record->arg2) && \
               (strcmp(curr->record.arg3,record->arg3) == 0) && \
               (strcmp(curr->record.arg4,record->arg4) == 0)
               )
            {
                // handle first item
                if (curr->prev == NULL)
                {
                    if (curr->next == NULL)
                    {
                        // only item?
                        list->head = NULL;
                        list->tail = NULL;
                    }
                    else
                    {
                        // more items?
                        list->head = curr->next;
                        list->head->prev = NULL;
                    }
                    free(curr);
                    break;
                }
    
                // handle last item
                if (curr->next == NULL)
                {
                    curr->prev->next = NULL;
                    list->tail = curr->prev;
                    list->tail->next = NULL;
                    free(curr);
                    break;
                }
    
                // handle middle item
                if (curr->prev != NULL && curr->next != NULL)
                {
                    curr->prev->next = curr->next;
                    curr->next->prev = curr->prev;
                    free(curr);
                    break;
                }
            } // found record
    
            // Next record
            curr = curr->next;
    
        } // while (curr != NULL)
    
        // No match
        if (curr == NULL)
        {
            // do nothing
        }
        pthread_mutex_unlock(&list->mutex);
    } // rem

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,736
    > (curr->record.arg1 == record->arg1) && \
    1. You don't need the \ at the end of these lines. You only need \ at the end of complicated #define code blocks.
    2. Make it a separate function you can call.

    Code:
    if ( record_equal(curr->record,record) ) {
      // do stuff
    }
    3. Your logic should be if / else if
    Code:
                if (curr->prev == NULL)
                {
                }
                else if (curr->next == NULL)
                {
                }
                else if (curr->prev != NULL && curr->next != NULL)
                {
                }
    You can then have a single free, and a single break.

    But it would seem to work as is, fwiw.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Double linked structure between 2 threads
    By Kishintai in forum C Programming
    Replies: 5
    Last Post: 06-05-2014, 03:55 AM
  2. HELP! Multiple threads access to global variables
    By thilar in forum C Programming
    Replies: 10
    Last Post: 10-29-2012, 06:46 PM
  3. How to access data from a Linked List?
    By gabrielksa in forum C Programming
    Replies: 2
    Last Post: 01-25-2011, 09:51 PM
  4. Replies: 1
    Last Post: 04-02-2009, 06:51 AM
  5. Can multiple linked lists share the same structure?
    By passy in forum C Programming
    Replies: 10
    Last Post: 08-28-2003, 04:38 PM

Tags for this Thread