在一个CPU核心的多线程上真的需要计数锁吗?

时间:2012-09-22 03:28:28

标签: multithreading operating-system thread-safety locking multiprocessing

如果我有一些代码看起来像这样(请忽略语法,我想在没有指定语言的情况下理解它):

count = 0

def countDown():
  count += 1

if __name__ == '__main__':
    thread1(countDown)
    thread2(countDown)
    thread3(countDown)

这里我有一个只有一个核的CPU,我真的需要锁定变量 count ,以防它被其他线程覆盖。

我不知道,但如果语言非常关注,请在 Java,C和Python 下解释一下,非常感谢。


谢谢大家,我现在明白我确实需要锁。但这是另一个问题,我什么时候需要使用多线程?

由于CPU只执行一个教师,似乎多线程需要更多时间来管理线程切换,并且无法节省计算时间。

6 个答案:

答案 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)

什么时候需要多线程?

对我来说,有两个不同的应用程序:

  • Parallell处理当多个线程 - 理想情况下每个核心只有一个 - 在很长一段时间内处理整个问题的一小部分。所需的代码和数据很小,并且 - 在最好的世界中 - 将适合核心的L1和L2缓存。这里的瓶颈 - 如果性能很重要 - 将是内存带宽以及如何尽可能少地使用它。
  • 另一种是当程序的不同组件或多或少彼此独立地运行并且处理要求随时间变化时。一个示例可以是邮件(SMTP)服务器,其具有至少三个独立组件:用于从SMTP客户端接收邮件的SMTP服务器,用于将邮件发送到其他SMTP服务器的SMTP客户端以及用于查找到的真实地址的名称客户端SMTP客户端应该发送邮件。

答案 5 :(得分:0)

其他海报已经很好地解释了锁定问题。

另一个问题也相当容易 - 大多数应用程序都是多线程的,可以通过多个可以阻止的I / O流来提高I / O性能。我现在正在打字。浏览器必须响应鼠标和键盘上的网络活动和用户输入。通常,它必须“同时”做到这两点。用户输入和网络通信分别非常慢和慢 - 两者都阻塞。因此,GUI和网络通信在不同的线程上运行。即使只有一个CPU内核也不需要这样做,而不会导致旧的“Windows 3.1”风格的“沙漏应用程序”,而GUI通常是无响应的。请注意,这个需要多线程的问题也适用于异步I / O - 这看起来像是在一个线程上运行,但是内核线程/池支持 - 大部分阻塞都被移入内核。

这就是单核盒子。您不能使用多个线程来加速CPU密集型计算,(事实上,如您所知,您将减慢它们的速度),但您可以将它们用于高性能I / O.当我们都拥有单核Pentiums和Windows 95时,许多应用都是多线程的 - 以优化I / O,而不是加速计算。