2008-09-23 96 views
11

阅读Test-and-Set Wikipedia entry之后,我仍然留下了一个问题:“测试和集合将用于什么?”什么是测试和设置?

我意识到你可以使用它来实现Mutex(如维基百科中所述),但它有什么其他用途?

回答

8

您可以在任何时候在任何时候将数据写入内存后使用它,并确保另一个线程在您启动后没有覆盖目标。很多lock/mutex-free algorithms采取这种形式。

1

基本上,考虑到原子性的巨大重要性,它的用途正好适用于互斥体。而已。

测试和设置是一个可以用两个其他指令执行的操作,非原子和更快(原子性在多处理器系统上承受硬件开销),因此通常不会因其他原因使用它。

13

一个很好的例子是“增量”。

说两个线程执行a = a + 1。假设a从值100开始。如果两个线程同时运行(多核),两者都将加载a作为100,增加到101,并将其存储回a。错误!

随着测试和设置,你说“设置a101,但只有当它的值为100。”在这种情况下,一个线程将通过该测试,但另一个线程将失败。在失败的情况下,线程可以重试整个语句,这次加载a101。成功。

这通常比使用互斥,因为速度快:

  1. 大部分时间没有竞争条件,所以更新情况,而无需获得某种互斥的。
  2. 即使在冲突期间,一个线程根本没有被阻塞,而另一个线程的旋转和重试速度要比它为了某些互斥锁而挂起自己的速度要快。
+0

+1你刚刚帮我解决了我正在处理的一个问题。 – 2011-12-01 21:16:26

+9

@ jason-cohen:这实际上是[Compare and Swap](https://en.wikipedia.org/wiki/Compare-and-swap)的描述。测试和设置通常只涉及值0和1. ** set **部分是指将指定内存位置的值设置为1.它返回前一个值,即1或0,并执行所有操作在一个单一的原子操作。 – 2013-06-29 04:48:25

0

当您需要获取共享值,对其执行操作并更改该值(假设其他线程尚未更改)时,会使用它。

至于实际应用,我最后一次看到它是在并发队列的实现中(队列可能被多线程推送/弹出而不需要信号或互斥)。

为什么要使用TestAndSet而不是互斥量?因为它通常比互斥锁需要更少的开销。在互斥体需要OS干预的情况下,TestAndSet可以作为CPU上的单个原子指令实现。在具有100个线程的并行环境中运行时,代码关键部分中的单个互斥量可能会导致严重的瓶颈。

5

想象一下,您正在撰写银行申请,而您的申请有要求从账户中提取十英镑(是的,我是英文的)。因此,您需要将当前帐户余额读入局部变量,减去提款,然后将余额写回内存。

但是,如果在读取值和写出它之间发生另一个并发请求,该怎么办?有可能该请求的结果将被第一个完全覆盖,并且帐户余额将不正确。

测试和设置帮助我们通过检查您的覆盖值是您认为应该是什么来解决该问题。在这种情况下,您可以检查余额是您读取的原始值。由于它是原子性的,因此它是不可中断的,因此在阅读和写作之间没有人能够从你之下拉出地毯。

解决同样问题的另一种方法是取出内存位置的锁。不幸的是,锁定非常难以正确,难以推理,存在可扩展性问题,并且在出现故障时表现不佳,所以它们不是理想的(但绝对实用的)解决方案。测试和设置方法构成了一些软件事务存储器的基础,它们乐观地允许每个事务同时执行,但是如果它们发生冲突,则将它们全部回滚。