我对这个问题感到困惑:
我有C ++功能:
void withdraw(int x) {
balance = balance - x;
}
balance
是一个全局整数变量,在开始时等于100
我们用两个不同的线程运行上面的函数:线程A和线程B.线程A运行withdraw(50)
,线程B运行withdraw(30)
。
假设我们不保护balance
,在以下序列中运行这些线程之后,balance
的最终结果是什么?
说明:
A1表示OS在线程A中执行函数withdraw
的第一行,A2表示OS在线程A中执行第二行函数withdraw
,B3表示OS执行第三行线程B中的函数withdraw
,依此类推。
顺序是OS如何调度线程A& B大概是。
我的回答是
balance
。上下文切换后,操作系统将balance
恢复为50)但是我的朋友不同意,他说balance
是一个全局变量。因此它不会保存在堆栈中,因此不受上下文切换的影响。他声称所有4个序列都导致20个。
那么谁是对的?我无法在他的逻辑中找错。
(我们假设我们有一个处理器,一次只能执行一个线程)
答案 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 ++代码有关。