2012-05-21 45 views
3

如果我有一个关键部分,我必须实现一个锁定它的方法。我看到了以下的变体:轮询锁是否实现关键部分的正确方法?

while(lock) 
{ 
    //do nothing 
} 
lock = true; 
// code of critical section 
lock = false; 

然而,我怀疑它,因为在理论上,几个线程可以执行while(lock)(检查,看看它的= FALSE),并进入临界区一起,因为while(lock)lock = true;不是在一个连续的块中执行的。我错了吗?或者这确实是一种不安全的方法?

+0

你需要一个锁,所以使用一个锁。 –

回答

3

这是“几乎安全”,即根本不安全。它缺少的正是你所看到的 - 多个线程可能会看到lock == false并进入关键部分。它需要一个原子操作,它必须被硬件支持 - 一种保证只有一个执行线程可以获得锁的方法。这就是说,如果你正在编写的系统可以在互斥排除失败的情况下继续存在,并且可以在偶尔的失败情况下工作(可能是日志记录或者偶然的错位输入不一定会导致完全失败的东西),那么这种模式可以“排序”工作...

+0

“它需要一个原子操作,它必须被硬件支持” - 这应该是汇编代码中的指令,或者有准备好的机制? –

+1

它是CPU指令集中的一条指令(或几条中的一条)。如果你的编译器支持这样的结构,它可以通过原始汇编代码或内联汇编代码进行访问。更好的办法是利用已经有正确的例程编写的线程/并发库,但你没有提到这是Linux与gcc或Windows与VC + +或其他... – twalberg

+0

好吧,谢谢你,将深入了解。我正在使用Embarcadero RAD Studio C++ Builder 2010. –

5

你是对的 - 这是不安全的。没什么比这更多的说。

编辑:不,真的,真的没有太多可以说这个构造。这是而不是自旋锁,也不像自旋锁。对于一个自旋锁,你需要的东西含糊这样的:

// note: incomplete, not reentrant, not intended for real use 
atomic_type spin_lock = 0; 

// enter the spin lock: 
int prev_value; 

while ((prev_value = test_and_set(&spin_lock, 1)) != 0 || spin_lock != 1) 
    ; 
// code of critical section 

// release the spin lock: 
test_and_set(&spin_lock, 0); 

这里最重要的一点是,进入自旋锁,你需要获得前值和设定新的价值原子。然后你必须确认你的写入锁从“非拥有”改为“拥有”状态。

+0

您也是正确的,但仅适用于第一句。还有很多话要说。 –

+0

@JensGustedt:关于线程安全编程(以及其他)肯定还有很多话要说,但关于这个特定的构造还不多说。 –

0

你试图实现的称为自旋锁。新的C标准C11实现了一个名为atomic_flag的原始数据类型,可以像那样使用它。几乎所有的现代硬件都支持它,但不幸的是,大多数编译器还不是完全支持语法级别的编译器,而是拥有自己的扩展。例如,gcc已经为此建立了__sync_lock_test_and_set__sync_lock_release

+0

这不是自旋锁,甚至不像自旋锁。 –