0

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

count = 0

def countDown():
  count += 1

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

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

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


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

由于CPU只会执行一个instructor,看起来多线程管理线程切换会花费更多时间,并不能节省计算时间。

4

6 回答 6

2

从技术上讲,一般来说是的。也许不是在这个特定的例子中。但是想象一下你的原子函数将包含几个指令。操作系统可以并且确实一次执行多个线程。它执行一个步骤中的一些步骤,然后切换回选择继续哪个进程/线程的操作系统。它可以启动所有线程并在它们之间切换。即使在一个 CPU 上。然后所有线程将在相同的内存地址上运行并共享变量。

编辑:回答第二个问题。当你有一个核心时,我可以想象只有一种情况需要多线程。这是您的一个线程可以锁定并且您需要在此期间对其进行监视或执行其他操作的时候。一个实际的例子是服务器。如果您想同时为多个客户端提供服务,则需要在它们之间切换。如果您在队列中为他们提供服务,那么一个坏客户可能会挂起整个过程。

如果你在做计算,你可以用它来分割 I/O 和计算。但它必须是一个非常极端的情况才能有用或需要。

于 2012-09-22T03:35:02.087 回答
1

是的,你可能还需要一把锁。你的countDown代码可能编译成这样的:

load global variable "count" into register x
x = x + 1
save register x into global variable "count"

如果中间有线程切换,那你就有麻烦了。您实际上不需要第二个核心来获得不良行为。

有时countDown可能会编译为原子指令。例如, 上有这样的说明x86,但我无法保证编译器会使用它们(除了自己编写程序集)。

于 2012-09-22T03:57:22.390 回答
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

它们有可能比锁更有效,因为它们在功能上比锁更受限制。

于 2012-09-22T04:08:38.610 回答
0

对于最简单的示例,我们创建多个线程共享一个变量并对其执行单个原子指令。无论任何线程在哪里被中断,它的状态要么完全在共享资源指令之前,要么完全在之后。

在这种情况下,x86 增量是原子的,因此是线程安全的。您不需要锁来保持一致性或幂等性。

于 2012-09-22T03:43:46.847 回答
0

什么时候需要多线程?

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

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

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

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

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

于 2012-09-22T09:04:33.763 回答