如果我有一些代码看起来像这样(请忽略语法,我想在没有指定语言的情况下理解它):
count = 0
def countDown():
count += 1
if __name__ == '__main__':
thread1(countDown)
thread2(countDown)
thread3(countDown)
这里我有一个只有一个核的CPU,我真的需要锁定变量 count ,以防它被其他线程覆盖。
我不知道,但如果语言非常关注,请在 Java,C和Python 下解释一下,非常感谢。
谢谢大家,我现在明白我确实需要锁。但这是另一个问题,我什么时候需要使用多线程?
由于CPU只执行一个教师,似乎多线程需要更多时间来管理线程切换,并且无法节省计算时间。
答案 0 :(得分:2)
从技术上讲,总的来说是的。也许不是在这个特定的例子中。但是想象一下你的原子函数会包含几条指令。操作系统可以并且确实一次执行多个线程 。它执行一个步骤,然后切换回OS,选择继续哪个进程/线程。它可以启动所有线程并在它们之间切换。即使在一个CPU上。然后所有线程将在相同的内存地址上运行并共享变量。
编辑:回答第二个问题。 当你有一个核心时,我只能想象一个你需要多线程的情况。当你的一个线程可以锁定并且你需要监视它或在这个时间做其他事情时。一个实际的例子是服务器。如果要同时为多个客户端提供服务,则需要在它们之间进行切换。如果你在队列中提供服务,一个坏客户端可能会挂起整个过程。
如果您正在进行计算,可以使用它来分割I / O和计算。但它需要是一个非常极端的情况才有用或需要。
答案 1 :(得分:1)
是的,您可能仍需要锁定。您的countDown
代码可能会编译成这样的内容:
load global variable "count" into register x
x = x + 1
save register x into global variable "count"
如果中间有一个螺纹开关,那么你就麻烦了。你实际上并不需要第二个核心来解决不良行为。
有时候countDown
可能会编译成原子指令。例如,x86
上有这样的指令,但是我无法保证编译器使用它们(除了自己编写程序集)。
答案 2 :(得分:1)
对于简单的事情,例如递增计数器,而不是使用锁,在c中你可以找到以线程安全的方式执行操作的原子函数。 GCC定义了这些原子内置函数,这些函数通常包含在每个特定环境中的公共函数调用中 http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Atomic-Builtins.html
Mac OS X定义了这些例如https://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
这些可能比锁定更有效,因为它们在功能上比锁定更有限。
答案 3 :(得分:0)
对于最简单的示例,我们创建多个共享单个变量并在其上执行单个原子指令的线程。无论线程在哪里被中断,其状态要么完全在共享资源上的指令之前或之后完全。
在这种情况下,x86增量是原子的,因此是线程安全的。您不需要锁来保持一致性或幂等性。
答案 4 :(得分:0)
什么时候需要多线程?
对我来说,有两个不同的应用程序:
答案 5 :(得分:0)
其他海报已经很好地解释了锁定问题。
另一个问题也相当容易 - 大多数应用程序都是多线程的,可以通过多个可以阻止的I / O流来提高I / O性能。我现在正在打字。浏览器必须响应鼠标和键盘上的网络活动和用户输入。通常,它必须“同时”做到这两点。用户输入和网络通信分别非常慢和慢 - 两者都阻塞。因此,GUI和网络通信在不同的线程上运行。即使只有一个CPU内核也不需要这样做,而不会导致旧的“Windows 3.1”风格的“沙漏应用程序”,而GUI通常是无响应的。请注意,这个需要多线程的问题也适用于异步I / O - 这看起来像是在一个线程上运行,但是内核线程/池支持 - 大部分阻塞都被移入内核。
这就是单核盒子。您不能使用多个线程来加速CPU密集型计算,(事实上,如您所知,您将减慢它们的速度),但您可以将它们用于高性能I / O.当我们都拥有单核Pentiums和Windows 95时,许多应用都是多线程的 - 以优化I / O,而不是加速计算。