我开始学习线程了,现在我开始讨论本书让我误解了用户级和内核级线程。
这本书非常强调差异并提出一个问题,说下面两个相似代码的输出是不同的,但是,据我所知,它们的输出对我来说似乎是相同的。
第一个是关于用户级线程:
int number = 0;
int main() {
fork()
if it is child {number--, return 0}
if it is parent {number++, wait till child return, print number}}
我的分析是,因为number--和number ++只需执行一次,输出将在这两次执行后打印出来,所以输出必须为0.
第二种情况是关于内核级线程:
int number = 0;
t1() {number--}
t2() {number++}
main() {
createThread(pass t1)
createThread(pass t2)
wait till both complete
print number
}
在这种情况下,同样的事情,内核创建两个线程,一个 - ,另一个++,所以它们都必须只执行一次。结果必须再次为0。
然而,这本书说输出是不同的,或者由于干预可能会有不同的输出,有人可以告诉我为什么吗?
答案 0 :(得分:2)
在第一种情况下,它不是创建线程,而是分支进程(查找fork()函数的描述)。分叉进程有自己的内存,从父进程复制,因此减少子进程中的数字的结果将不会影响父进程。父进程中打印号的结果为1。
答案 1 :(得分:1)
即使你写了一条指令i++
或i--
,它也可能被翻译成机器语言中的多条指令。如果您正在使用内核线程,则这两个计算可以在不同的核上运行,每个核都缓存“{”值i
。在这种情况下实际写入内存的结果是未定义的,因为硬件和编译器假设没有人在后面修改数据。
答案 2 :(得分:0)
在线程情况下,由于可能的数据竞争,可能会获得1
或甚至-1
作为最终值。由于无法保证在线程1完成后线程2将被启动,反之亦然,如果没有正确的同步,两个线程可能会在大约相同的时间开始并看到0
的初始值。然后,根据哪个线程完成第二个,该值将是1
或-1
而不是0
。为了避免这种情况,必须使用关键部分或原子输入/减量之类的同步习语。