Home > Software engineering >  Using a pointer to a Mutex (pthread_mutex_t *) in a structure, Instead of a global Mutex
Using a pointer to a Mutex (pthread_mutex_t *) in a structure, Instead of a global Mutex

Time:01-19

I'm using a lock (pthread_mutex_t) in a program that launches a number of threads, all threads receives a pointer to a structure, which contains a pointer to this mutex.

So there is one initialized mutex, and all structures have a pointer to it but it doesn't works well, I don't understand why?

Here is some example code, I tried to make it as minimal as possible.

Lets call my program duck:

duck.c

# include "duck.h"

void    *exec_threads(void *arg)
{
    struct s_duck   *duck;

    duck = (struct s_duck*)arg;
    pthread_mutex_lock(duck->mutex);
    printf("duck nbr %i\n", duck->n);
    pthread_mutex_unlock(duck->mutex);
    return (NULL);
}

int main(void)
{
    pthread_t       *id;
    pthread_mutex_t *mutex;
    struct s_duck   *duck;
    int             n;
    int             i;

    n = 5; // number of threads
    id = malloc(sizeof(int) * n); // allocate id[n]
    mutex = malloc(sizeof(pthread_mutex_t)); // allocate mutex
    pthread_mutex_init(mutex, NULL); // init mutex
    duck = init_chain_ducks(mutex, n); // create chained list of structure
    i = 0;
    while (i < n)
    {
        pthread_create(&id[i], NULL, &exec_threads, duck); // launch threads
        duck = duck->next;
        i  ;
    }
    i = 0;
    while (i < n)
    {
        pthread_join(id[i], NULL); // join threads
        i  ;
    }
    write(1, "the end\n", 8);
    return (0);
}

duck_chain.c

# include "duck.h"

struct s_duck   *init_chain_ducks(pthread_mutex_t *mutex, int n)
{   
    struct s_duck   *new;
    struct s_duck   *duck;
    int         i;

    i = n;
    duck = NULL;
    while (i > 0)
    {
        new = malloc(sizeof(struct s_duck));
        new->n = i;
        new->mutex = mutex; // this is where the pointer to the mutex is stored
        new->next = duck;
        duck = new;
        i--;
    }
    return (duck);
}

duck.h

#ifndef DUCK_H
# define DUCK_H

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <pthread.h>

struct s_duck
{
    int             n;
    pthread_mutex_t *mutex;
    struct s_duck   *next;
};

struct s_duck   *init_chain_ducks(pthread_mutex_t *mutex, int n);

#endif

If i use a global variable for the mutex instead, it works well. But with the pointer in the structure, i get something like an undefined behaviour:

Most of the time i get this output :

duck nbr 1
duck nbr 3
duck nbr 4
duck nbr 5
duck nbr 2
[2]    18914 segmentation fault (core dumped)  ./a.out

The segfault happens during the pthread_join() but i also get those two errors often:

duck nbr 1
duck nbr 2
[wait indefinitely]

Or:

duck nbr 1
duck nbr 4
duck nbr 3
a.out: ../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
[2]    20394 abort (core dumped)  ./a.out

I must be doing some basic mistake, but I don't know where.

(compilation : gcc duck.c duck_chain.c -lpthread)

CodePudding user response:

pthread_t       *id;

id = malloc(sizeof(int) * n); // allocate id[n]

id is not an int - it's pthread_t. Should be sizeof(pthread_t). Use a little trick and use the pointer points to.

id = malloc(sizeof(*id) * n);

Compile with -g -Wall -Wextra -fsanitize=undefined,address - sanitizer will help you catch such mistakes.

  •  Tags:  
  • Related