线程编程中的锁和原子操作之间的关系

时间:2019-03-16 22:40:29

标签: multithreading locking atomic

所有锁是否都使用原子操作实现?在某些书中,它说“一个锁需要几个原子操作”。我认为原子操作和锁是不同的东西。但是看来我错了。锁和原子操作之间是什么关系?

1 个答案:

答案 0 :(得分:1)

锁和原子 锁是一种保护机制,用于对受锁保护的某些数据执行复杂的,线程不安全的操作。 Atomic operations是永远无法仅在过程中观察到的操作,并且如果多个线程同时访问相同的变量也不会中断操作(请注意,在C ++中,对其执行原子操作的变量也称为原子操作)。锁是使用原子操作实现的抽象概念。

如何使用互斥锁/锁 mutex是执行锁定的标准方法:互斥锁始终保护与之关联的某些变量。它是锁定的或未锁定的,一次只能锁定一个线程。互斥锁处于锁定状态时,线程可以对其受保护的变量执行线程不安全的操作,并确保没有其他线程可以干扰或观察到持有该锁的线程所做的部分更改。线程修改完变量后,它可以解锁互斥锁,以便其他线程现在可以访问受保护的变量(通过互斥锁自己)。

请注意,只要线程想要以任何方式访问任何受保护的变量,它都需要锁定关联的互斥锁。否则,将不再保证线程不会干扰彼此的工作。

如何实现锁? 据我所知,锁/互斥锁始终使用原子操作来实现。 atomic exchange 是这样的一种操作:它允许您从变量中读取一个值,并以原子方式向其写入新值,因此没有其他线程可以干扰此过程或观察它已经完成了一半。互斥锁将使用原子布尔(true = LOCKED,false = UNLOCKED)实现,并通过执行以下操作来锁定它:

while(mutex.locked.exchange(LOCKED) == LOCKED);

这总是将互斥锁设置为LOCKED,并读取先前的值,如果为UNLOCKED,则完成操作。在这种情况下,我们是唯一将互斥锁从UNLOCKED设置为LOCKED的线程。

解锁非常简单:mutex.locked = UNLOCKED;只需将互斥锁设置为UNLOCKED,然后它就可以被其他线程再次锁定。

注意 为简单起见,我确实忽略了memory ordering,这是原子的一个方面,它处理一个线程对其他线程可见的更改的顺序(对于某些内存顺序,更改的观察顺序与在其中创建它们,并且多个线程甚至可能看到顺序不一致的更改)。进入内存顺序非常复杂。

结论 根据一般经验,除非您真的知道自己在做什么,否则应始终使用互斥锁和锁,而不要使用原子。尽管互斥锁较慢,但它们已经足够复杂以至于无法使用,并且易于正确使用。它们自动处理所做更改的可见性,因此您的程序变得更易于理解和编写。