【问题标题】:Using a counting semaphore how do I create a recursive mutex使用计数信号量如何创建递归互斥锁
【发布时间】:2018-12-17 03:16:45
【问题描述】:

我在裸机环境中运行,所以任何回答说只使用你拥有的东西都不适用,因为我没有任何东西。我正在编写一个系统驱动程序,但我需要递归互斥锁,但我不知道如何实现它们。我目前只有一个作为自旋锁运行的计数信号量。是否可以从信号量创建递归互斥锁,或者我是否必须创建另一个同步原语,如果可以,如何?不需要代码,我只是想知道步骤。

【问题讨论】:

  • 如果是裸机,那么您如何拥有一个系统来为其编写系统驱动程序?为什么需要没有系统的递归互斥锁?
  • 它并不是传统意义上的裸机。我正在编写自己的系统,并且正在实现 FAT32 文件系统。

标签: c logic bare-metal


【解决方案1】:

如果您对数据竞争下发生的事情有一些相当薄弱的好属性,那么它本质上是轻而易举的:

/* data structure */
struct my_mutex {
    sem_t sem;
    volatile tid_t owner;
    unsigned count;
} m;

/* lock operation */
if (m->owner == self) { // formally a race
    m->cnt++;
} else {
    sem_wait(&m->sem);
    m->owner = self; // where self is tid of calling thread
}

/* unlock operation */
if (m->count > 0) {
    m->count--;
} else {
    m->owner = 0;
    sem_post(&m->sem);
}

请注意,假设赛车读取从某些可能的排序中读取了一些价值,则没有任何排序可以让您在自己是所有者时无法将自己视为所有者,在您不是时也不会将自己视为所有者。但是,如果您将它们视为正式未定义,则无效。

如果你不能这样做,你通常需要一个普通的 mutex + condvar 来模拟一个递归的 mutex,所以首先要弄清楚如何从一个信号量制作一个 condvar。

如果您的编译器具有 _Atomic 并支持线程 ID 的正确大小的原子(上面的抽象 tid_t 类型;在裸机上,这是您要定义的类型),您可以使 tid_t owner 成员 @ 987654325@并替换测试:

if (m->owner == self)

与:

if (atomic_load_explicit(&m->owner, memory_order_relaxed) == self)

volatile 限定符(在很大程度上是不必要的,但作为向编译器发出的一个信号,它不应该拆分或组合负载,这有助于在没有原子的情况下实现我的目标“弱好的属性”)可以被删除。

【讨论】:

  • 我很确定如果 m->owner 属于 _Atomic 类型,即使是 memory_order_relaxed 访问,它也已明确定义。
  • 是的,如果你有一个支持原子的 C11 编译器,那么它是明确定义的。
  • _Atomic 类型对于裸机是安全的还是我需要使用 test 来实现它并在 asm 中设置?
  • 理论上,机器没有合适大小的指令的原子类型将使用锁来实现,这可能无论如何都可以,但这并不是你真正需要担心的事情对于可以用于线程标识符的合理类型。如果您可以在 asm 中实现它,那么正确实现原子的编译器应该将其作为无锁原子。
  • 请注意,使用 EOF 推荐的宽松顺序,您通常甚至不依赖机器级别的任何特殊原子/屏障指令。它更接近于 volatile - 限制编译器可以执行的转换 - 如果你被 C11 之前的编译器困住,这将是我书中放松顺序原子的合适破解。
猜你喜欢
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
相关资源
最近更新 更多