c - 如何以原子方式解锁和销毁互斥体

标签 c multithreading unix mutex

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

我们先看一段代码:(以下代码来自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。

然而,此时发生了上下文切换。线程2开始执行。

thread2 锁定锁 fp->f_lock 然后执行某些操作。但在thread2解锁之前,又发生了上下文切换。

线程2停止执行,线程1开始执行。 thread1 破坏了锁,我们都知道会产生错误。

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

最佳答案

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

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

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

永远不可能有线程 1 调用 foo_rele() 而线程 2 要么知道它永远不会再接触 fp 要么线程 2 已经退出。

关于c - 如何以原子方式解锁和销毁互斥体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18431722/

相关文章:

C - 取消分配整数列表

c - 作业 : Why is argv[2] defined?

java - 为什么Java在进入无限循环时会挂起主线程?

c# - 在 windows 窗体中实现加载器,如 web 应用程序

regex - 使用 sed 将多个栏(特殊字符)替换为制表符

c - 在多对象/结构 X11 显示的情况下如何从窗口中删除对象?

c - 我是否需要在 C++/CLI 中删除非托管对象

c - 使用 GNU 程序集访问指向结构的 *next 指针

c - C 中的单线程与 pthread 的多线程

shell - 旋转文本文件