什么是线程的“关键部分”?

一个

由 () ,其中

可以是或

非-。 A 退出

,由

()。

– 理解线程,Linux

另外,锁的用途是什么?

其他人给出了非常好的定义。 这是一个经典的例子:

= 0 # 那个“”。

= .Lock()

def ce(增量):

和:

# 就是这个块。

+= 增量

假设 += 运算符由三个子组件组成:

如果您没有 with 语句并且并行执行两个 ce 调用,则最终可能会以危险的方式交错三个子组件操作。 假设您同时调用 ce(100)(又称为 pos)和 ce(-100)(又称为 neg)。 这可能会发生:

pos = .(=ce, args=[100])

负 = .(=ce, args=[-100])

pos.start(), neg.start()

由于您没有强制操作以离散块的形式发生,因此可能会出现三种可能的结果(-100、0、100)。

with [lock] 语句是一个单一的、不可分割的操作,它表示:“让我成为执行此代码块的唯一线程。如果有其他东西正在执行,那很酷 – 我会等待。” 这确保了更新是“线程安全”(并行安全)的。

注意:此模式有一个警告:您必须记住每次要操作时都要获取(通过 with )以保持代码线程安全。 有多种方法可以减少此漏洞,但这是另一个问题的答案。

编辑:回想起来,可能需要提到的是 with 语句隐式调用锁上的阻塞 – 这是上面线程对话框的“我会等待”部分。 相反,非阻塞获取会说“如果我不能立即获取锁,请告诉我”,然后依赖您来检查是否获取了锁。

10

11

12

13

14

15

16

# 这是安全的。

锁 = .Lock()

def 运行():

if LOCK.(False): # 非–我们明白了

(“拿到锁了!”)

锁。()

别的:

(“没拿到锁。也许下次吧”)

.(级别=.INFO)

= [.(=运行) for i in range(100)]

对于:

。开始()

我还想补充一点,锁的主要目的是保证获取的原子性(跨线程的不可分割性),这是简单的布尔标志无法保证的。 原子操作的语义大概也是另一个问题的主题。

代码的关键部分是一次只能由一个线程执行的代码。 以聊天服务器为例。 如果每个连接(即每个最终用户)有一个线程,那么一个“关键部分”就是假脱机代码(将传入消息发送到所有客户端)。 如果多个线程尝试同时假脱机处理一条消息,则会出现交错,这显然一点都不好。

锁是可用于同步对关键部分(或一般资源)的访问的东西。 在我们的聊天服务器示例中,锁就像一个上锁的房间,里面有一台打字机。 如果有一个线程(输入消息),则其他线程不能进入房间。 一旦第一个线程完成,他就会打开房间并离开。 然后另一个线程可以进入房间(锁定它)。 “”锁只是意味着“我得到了房间。”

“关键部分”是一段代码,为了正确,必须确保一次只有一个控制线程可以位于该部分中。 通常,您需要一个临界区来包含将值写入内存的引用,该引用可以在多个并发进程之间共享。

好了,今天的主题就讲到这里吧,不管如何,能帮到你我就很开心了,如果您觉得这篇文章写得不错,欢迎点赞和分享给身边的朋友。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注