Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to safely and correctly destroy a mutex in Linux using pthread_mutex_destroy?

I read about APUE 3rd, 11.6.1 Mutexes, there is an example about lock and unlock a mutex in this chapter:

struct foo {
    int             f_count;
    pthread_mutex_t f_lock;
    int             f_id;
    /* ... more stuff here ... */
};

struct foo *
foo_alloc(int id) /* allocate the object */
{
    struct foo *fp;

    if ((fp = malloc(sizeof(struct foo))) != NULL) {
        fp->f_count = 1;
        fp->f_id = id;
        if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
            free(fp);
            return(NULL);
        }
        /* ... continue initialization ... */
    }
    return(fp);
}

void
foo_hold(struct foo *fp) /* add a reference to the object */
{
    pthread_mutex_lock(&fp->f_lock);
    fp->f_count++;
    pthread_mutex_unlock(&fp->f_lock);
}

void
foo_rele(struct foo *fp) /* release a reference to the object */
{
    pthread_mutex_lock(&fp->f_lock);
    if (--fp->f_count == 0) { /* last reference */
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    } else {
        pthread_mutex_unlock(&fp->f_lock);
    }
}

In foo_rele, there is a race condition between pthread_mutex_unlock and pthread_mutex_destroy: B thread can call pthread_mutex_lock between pthread_mutex_unlock and pthread_mutex_destroy in A thread which will cause undefined behavior ("Attempting to destroy a locked mutex results in undefined behavior").

Am I right? If I'm right, then, how to make it work right or how to safely and correctly destroy a mutex in Linux using pthread_mutex_destroy?

like image 727
cong Avatar asked Sep 21 '17 13:09

cong


People also ask

Should mutex be destroyed?

It shall be safe to destroy an initialized mutex that is unlocked. Attempting to destroy a locked mutex results in undefined behavior. The pthread_mutex_init() function shall initialize the mutex referenced by mutex with attributes specified by attr.

What happens if you don't unlock a mutex?

If you don't, then a typical mutex is held in process memory and will simply cease to exist along with anything that might have access to it when the process terminates.

Can Pthread_mutex_unlock block?

Yes, it is a blocking call and will block until it gets the lock.


Video Answer


1 Answers

The POSIX spec for pthread_mutex_destroy() says:

It shall be safe to destroy an initialized mutex that is unlocked.

Which means that if thread B calls pthread_mutex_unlock() in the else clause of the if statement in foo_rele() then it's safe for thread A to call pthread_mutex_destroy() because it can only have gotten there after thread B's pthread_mutex_unlock() call has unlocked the mutex.

All of this is assuming that the reference counting is correct, such that some other thread cannot increment the count from 0 -> 1 after thread A has unlocked the mutex. In other words, at the point where the refcount drops to 0, there can't be another thread that might possibly call foo_hold().

APUE mentions this in the explanation right after the example code:

In this example, we have ignored how threads find an object before calling foo_hold. Even though the reference count is zero, it would be a mistake for foo_rele to free the object’s memory if another thread is blocked on the mutex in a call to foo_hold. We can avoid this problem by ensuring that the object can’t be found before freeing its memory. We’ll see how to do this in the examples that follow.

like image 71
Michael Burr Avatar answered Oct 29 '22 12:10

Michael Burr