线程上下文切换如何与全局变量一起使用?

时间:2015-06-24 22:56:02

标签: multithreading context-switch

我对这个问题感到困惑:
我有C ++功能:

void withdraw(int x) {
     balance = balance - x;
}

balance是一个全局整数变量,在开始时等于100 我们用两个不同的线程运行上面的函数:线程A和线程B.线程A运行withdraw(50),线程B运行withdraw(30)

假设我们不保护balance,在以下序列中运行这些线程之后,balance的最终结果是什么?

  1. A1-> A2-> A3-> B1-> B2-> B3
  2. B1-> B2-> B3-> A1-> A2-> A3
  3. A1-> A2-> B1-> B2-> B3-> A3
  4. B1-> B2-> A1-> A2-> A3-> B3
  5. 说明:

    • A1表示OS在线程A中执行函数withdraw的第一行,A2表示OS在线程A中执行第二行函数withdraw,B3表示OS执行第三行线程B中的函数withdraw,依此类推。

    • 顺序是OS如何调度线程A& B大概是。

    我的回答是

    1. 20
    2. 20
    3. 50(在上下文切换之前,操作系统保存balance。上下文切换后,操作系统将balance恢复为50)
    4. 70(与上述类似)
    5. 但是我的朋友不同意,他说balance是一个全局变量。因此它不会保存在堆栈中,因此不受上下文切换的影响。他声称所有4个序列都导致20个。

      那么谁是对的?我无法在他的逻辑中找错。

      (我们假设我们有一个处理器,一次只能执行一个线程)

5 个答案:

答案 0 :(得分:0)

除非您使用的线程标准指定,否则无法知道。大多数典型的线程标准都没有,所以通常无法知道。

你的回答听起来像胡说八道。操作系统不知道balance是什么,也没有办法围绕上下文切换做任何事情。此外,线程可以在没有上下文切换的情况下同时运行。

你朋友的回答听起来也像胡说八道。他怎么知道它不会被编译器缓存在寄存器中,因此一些修改会扼杀以前的修改?

但重点是,你们两个都在猜​​测可能会发生什么。如果你想有用地回答这个问题,你必须谈谈保证会发生什么。

答案 1 :(得分:0)

显然是家庭作业,但在提出要求之前通过实际工作得以保存。

首先,忘记上下文切换。上下文切换与问题完全无关。假设您有多个处理器,每个处理器执行一个线程,并且每个处理器以未知速度进行,在不可预测的时间停止和启动。更好的是,假设这种停止和存储是由敌人控制的,他会试图打破你的程序。

由于上下文切换无关紧要,操作系统不会保存或恢复任何内容。它不会触及变量平衡。只有你的两个线程会。

你的朋友绝对是完全错的。恰恰相反。由于balance是一个全局变量,因此两个线程都可以读取和写入它。但是,你不会遇到他们可能以不明的顺序阅读和写下的问题,正如你所研究的那样,情况更糟。他们可以同时访问它,如果一个线程修改数据而另一个线程读取它,你就会遇到竞争条件,任何事情都可能发生。您不仅可以获得任何结果,您的程序也可能崩溃。

如果balance是保存在堆栈上的局部变量,那么两个线程都会拥有自己的变量,并且不会发生任何错误。

答案 2 :(得分:0)

考虑这一行:

balance = balance - x;

线程A读取余额。它是100.现在,线程A减去50和... oops

线程B读取余额。它是100.现在,线程B减去30并更新变量,现在是70。

...线程A继续并更新变量,现在是50.您刚刚完全丢失了线程B的工作。

线程不执行"代码行" - 他们执行机器指令。全局变量是否受上下文切换的影响并不重要。重要的是读取变量时,写入时,每个线程,因为值是"从架子上取下来"并修改,然后"放回"。一旦第一个线程读取了全局变量并且正在使用值"在某个空间"中,第二个线程就无法读取全局变量,直到第一个线程写入更新后的值。

答案 3 :(得分:0)

考虑这一行:

balance = balance - x;

线程A读取余额。它是100.现在,线程A减去50和... oops

线程B读取余额。它是100.现在,线程B减去30并更新变量,现在是70。

...线程A继续现在更新变量,现在是50.你刚刚失去了线程B的工作。

线程不执行“代码行” - 它们执行机器指令。全局变量是否受上下文切换的影响并不重要。重要的是读取变量时,它被写入时,由每个线程,因为值是“从架子上”并被修改,然后“放回” ”。一旦第一个线程读取全局变量并使用值“空间某处”,第二个线程就不能读取全局变量,直到第一个线程写入更新后的值。

答案 4 :(得分:0)

简单而简短的c ++答案:对共享变量的非同步访问是未定义的行为,因此任何事情都可能发生。该值可以是例如是100,70,50,20,42或-458995。程序可能崩溃或不崩溃。从理论上讲,它甚至可以订购披萨。

执行的实际机器代码通常远离程序的外观,并且在未定义的行为的情况下,您不再保证,实际行为与您编写的c ++代码有关。