【问题标题】:MUTEX process synchronization - why does common lock variable not work?MUTEX 进程同步 - 为什么普通锁变量不起作用?
【发布时间】:2015-09-02 16:04:34
【问题描述】:

在我的大学幻灯片中,老师写道,这种解决 MUTEX 问题的方法不起作用。为什么?

lock = true 表示临界区已经有进程

  1. Process1 检查锁,发现它是假的
  2. Process2 中断 Process1
  3. Process2 检查锁,它仍然是假的
  4. Process2 将 lock 设置为 true 并进入临界区
  5. Process1 再次检查锁定,将其设置为 true 并进入临界区。 (怎么办?为什么读的不是真的,所以进不去?)

【问题讨论】:

  • 发布一个实际的解决方案将帮助我们理解为什么它不起作用......我有几个猜测,但在我看到代码之前我不会发表评论。
  • 如果在您的程序中,如果您正在创建多个线程,并且您知道多个线程可以同时运行,那么可能发生的情况是,假设两个线程都将锁变量读取为 false同时,两者都允许在关键代码部分输入它。并且还可以说由于您的硬件或任何其他原因,一次只运行一个胎面,那么由于线程调度也可能发生这种竞争情况
  • 幻灯片中没有代码。这 5 个步骤与幻灯片中的一样,只是从德语翻译成英语。我认为这与获取和设置锁定值有关,而不是一个原子操作(或者是其他什么?),但我不明白为什么它不是原子的。
  • 真的无法理解老师的意思。基本上,这里是说某事因为某某而无法工作。但由于我们不知道这是什么东西,所以除了改写那 5 张幻灯片之外,不可能告诉你那里有什么问题,但这当然没有太大帮助。

标签: multithreading parallel-processing mutex


【解决方案1】:

假设您的“锁定”变量只是一个变量,那么检查变量值然后有条件地设置该变量的代码可以是多个指令。

考虑以下伪代码实现:

  • 将“锁定”读入寄存器 A
  • 将寄存器 A 与零进行比较
  • 如果比较结果为假,跳到最后
  • 将“1”写入“锁定”。

例如,考虑一下 C# 中的这段代码:

public static class Program
{
    private static int locked = 0;

    private static bool GetLock()
    {
        if( locked == 0 )
        {
            locked = 1;
            return true;
        }
        else
        {
            return false;
        }
    }
}

并考虑它的反汇编:

            if( locked == 0 )
00000000  cmp         dword ptr [0003E4F0h],0 
00000007  jne         0000000000000019 
            {
                locked = 1;
00000009  mov         dword ptr [0003E4F0h],1 
                return true;
00000013  mov         eax,1 
00000018  ret 
            }
            else
            {
                return false;
00000019  xor         eax,eax 
0000001b  ret 

现在考虑当两个线程同时尝试执行此操作时会发生什么:

  • 线程 1:读取 'locked' 为 0,进入 'if' 语句。
  • OS 线程调度程序决定更改 CPU 上的线程
  • 操作系统将线程 2 放在 CPU 上。
  • 线程2:读取'locked'为0,进入'if'语句
  • 线程 2:将 '1' 写入 'locked' 以表明它已获得它。
  • 线程 2:返回 true 表示它已获取它。
  • OS 线程调度程序决定更改 CPU 上的线程
  • 操作系统将线程 1 放在 CPU 上。
  • 线程 1:已经在 'if' 语句中,所以它执行下一条指令
  • 线程 1:将 '1' 写入 'locked' 以表明它已获得它
    • 但是糟糕,该变量已设置为 1,因为其他人获得了它。
  • 线程 1:返回 true 表示它认为它获得了锁(它没有)。

现在无论线程 1 和线程 2 为工作做什么(可能更新内存中的帐户余额)都将相互覆盖。如果这两个线程试图发布两个事务 - 添加 1000 并删除 500 - 现在它们没有独占访问权限会发生以下情况:

  • 线程 1:从帐户余额中读取“1000”。
  • 线程 2:从帐户余额中读取“1000”。
  • 线程 1:计算新余额 1000 + 1000 = 2000。
  • 线程 2:计算新余额 1000 - 500 = 500。
  • 线程 1:将新余额 2000 写入内存。
  • 线程 2:将新余额 500 写入内存。

现在由于线程错误,我的帐户余额少了 1000 美元。

【讨论】:

  • 是的,我想这就是老师的意思。下一张幻灯片表明机器级别的测试和设置锁定解决方案更好,因为它解决了检查和设置不是一条指令的问题。第二种选择是信号量变量
  • @DBRN:“第二种选择是信号量变量”- 是的,但是你如何实现信号量 :) 答案是架构级原子指令,如果你有一个多核架构尤其重要.最终,您必须要求 CPU 执行某种原子指令。维基百科上的自旋锁页面很有启发性:en.wikipedia.org/wiki/Spinlock
猜你喜欢
  • 2021-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 2019-02-08
  • 1970-01-01
相关资源
最近更新 更多