【问题标题】:how to unlock and destroy a mutex atomically如何以原子方式解锁和销毁互斥锁
【发布时间】:2013-08-28 05:03:10
【问题描述】:

我正在阅读史蒂文斯的书:apue。 2e。我遇到了一个关于 Mutex 的问题。

先看一段代码:(以下代码来自apue 2e的图11.10)

#include <stdlib.h>
#include <pthread.h>

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

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

    if((fp = malloc(sizeof(struct foo))) != NULL){
        fp->f_count = 1;
        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); /* step 1 */
        pthread_mutex_destroy(&fp->f_lock); /* step 2 */
        free(fp);
    }else{
        pthread_mutex_unlock(&fp->f_lock);
    }
}

假设我们有两个线程:thread1 和 thread2。 thread1 正在运行。

它调用函数 foo_rele 并完成了第 1 步的执行(见上文), 并准备执行step2。

但是,此时会发生上下文切换。然后thread2开始执行。

thread2 锁定锁 fp->f_lock 然后做一些事情。但在thread2解锁之前,上下文切换再次发生。

thread2 停止执行,thread1 开始执行。 thread1 销毁锁,我们知道所有错误生成。

所以,我的问题是:上面提到的情况有可能发生吗? 我们如何避免它,是否有任何接口(API)可以原子地解锁和销毁互斥锁​​?

【问题讨论】:

    标签: c multithreading unix mutex


    【解决方案1】:

    我同意 usr (+1),设计是错误的。

    一般来说,在一个线程可以销毁任何东西之前,它必须确定所有其他线程都已完成使用它。这需要某种其他形式的线程间同步。您需要的是一种方法,线程 1 可以告诉线程 2 需要释放资源,并让线程 2 确认这一点,以便线程 1 可以调用 foo_rele() 确定线程 2 不会尝试使用 fp以后再。或者,线程 2 告诉线程 1 它不再需要 fp 并且线程 1 调用 foo_rele() 作为结果。

    这可以通过多种方式完成。一种是线程1在锁的保护下设置一个标志,然后等待线程2退出。同时,线程 2 最终绕过来看到标志,然后退出。这会释放线程 1,然后调用 foo_rele()。另一种方式是通过管道传递消息(我首选的线程间同步方式);类似于线程 1 -> 线程 2,“请停止使用 fp”:线程 2 -> 线程 1,“好的”(当然,基于枚举更好定义的消息集是可取的,但你明白我的意思) .

    你永远不能拥有的是线程 1 调用 foo_rele() 而没有线程 2 知道它永远不能再接触 fp 或者线程 2 已经退出。

    【讨论】:

      【解决方案2】:

      这不是很好的设计,因为 thread2 访问了一个可能已经被销毁的对象。添加一个引用(增量f_count之前开始线程2。这样,thread2 就已经开始保证对象在运行时是稳定的。

      【讨论】:

        猜你喜欢
        • 2013-06-14
        • 2018-05-23
        • 2021-06-10
        • 1970-01-01
        • 2015-05-31
        • 2021-02-03
        • 2022-07-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多