Multithreading 互斥锁:什么是;“封锁”;什么意思?

Multithreading 互斥锁:什么是;“封锁”;什么意思?,multithreading,locking,thread-safety,mutex,blocking,Multithreading,Locking,Thread Safety,Mutex,Blocking,我一直在阅读关于多线程和共享资源访问的文章,其中一个(对我来说)新概念是互斥锁。我似乎无法发现的是,发现“关键部分”被锁定的线程的实际情况。它在许多地方说线程被“阻塞”,但这意味着什么?它是否已暂停,以及在解除锁后是否会恢复?或者它会在“运行循环”的下一次迭代中重试 我之所以问这个问题,是因为我想让系统提供的事件(鼠标、键盘等)在主线程上传递,并在次线程的运行循环中的一个非常特定的部分进行处理。因此,无论传递什么事件,我都在自己的数据结构中排队。显然,数据结构需要一个互斥锁,因为它正在被两个线程

我一直在阅读关于多线程和共享资源访问的文章,其中一个(对我来说)新概念是互斥锁。我似乎无法发现的是,发现“关键部分”被锁定的线程的实际情况。它在许多地方说线程被“阻塞”,但这意味着什么?它是否已暂停,以及在解除锁后是否会恢复?或者它会在“运行循环”的下一次迭代中重试


我之所以问这个问题,是因为我想让系统提供的事件(鼠标、键盘等)在主线程上传递,并在次线程的运行循环中的一个非常特定的部分进行处理。因此,无论传递什么事件,我都在自己的数据结构中排队。显然,数据结构需要一个互斥锁,因为它正在被两个线程修改。缺少的难题是:当一个事件在主线程上的函数中传递时会发生什么,我想对它进行排队,但队列被锁定了?主线程将被挂起,还是仅仅跳过锁定的部分并超出范围(丢失事件)?

阻塞就是这样的意思。它被封锁了。它将不会继续,直到我们能够。您不会说您正在使用哪种语言,但大多数语言/库都有锁对象,您可以在其中“尝试”获取锁,然后根据是否成功继续并执行不同的操作


但是,例如,在Java同步块中,线程将暂停,直到它能够获取监视器(互斥锁、锁)。
java.util.concurrent.locks.Lock
接口描述了在锁获取方面具有更大灵活性的锁对象。

最简单的方法是将被阻止的线程置于等待(“休眠”)状态,直到持有它的线程释放互斥锁。此时,操作系统将“唤醒”等待互斥锁的一个线程,让它获取互斥锁并继续。这就好像操作系统只是把阻塞的线程放在一个架子上,直到它有了需要继续的东西。在操作系统将线程从架子上取下之前,它不会做任何事情。确切的实现——下一步执行哪个线程,它们是被唤醒还是排队——将取决于您的操作系统以及您使用的语言/框架。

阻塞意味着执行会被卡住;通常,系统将该线程置于休眠状态,并将处理器让给另一个线程。当一个线程试图获取互斥体时被阻止,当互斥体被释放时,执行会恢复,尽管如果另一个线程在它可以之前获取互斥体,该线程可能会再次被阻止

通常会有一个try-lock操作,如果可能,它会获取互斥锁,如果不可能,它将返回一个错误。但您最终将不得不将当前事件移动到该队列中。此外,如果延迟将事件移动到处理它们的线程,应用程序将变得无响应

队列实际上是一种不使用互斥的情况。例如,Mac OS X(可能还有iOS)提供了
osatomiceQueue()
OSAtomicDequeue()
函数(请参见
man-atomic
),这些函数利用处理器特定的原子操作来避免使用锁


但是,为什么不将主线程上的事件作为主运行循环的一部分进行处理呢?

回答这个问题太晚了,但我可以帮助理解。我说的更多的是从实现的角度,而不是理论文本

“阻塞”一词是一种技术上的同音词。人们可以用它来睡觉,或者仅仅是等待。该术语必须在使用上下文中理解

阻塞意味着等待-假设在SMP系统上,线程B想要获取由其他线程a持有的自旋锁。其中一种机制是禁用抢占并在处理器上保持自旋,除非B获得它。另一种可能也是有效的机制是允许其他线程使用处理器,以防B不容易获得。因此,我们调度出线程B(因为启用了抢占),并将处理器分配给其他线程C。在这种情况下,线程B只是在调度程序队列中等待,然后轮到它返回。要知道B不是在睡觉,而是被动地等待,而不是忙着等待和燃烧处理器周期。在BSD和Solaris系统上,有类似于旋转栅门的数据结构来实现这种情况


阻塞意味着睡眠-如果线程B改为进行系统调用,如read()等待来自网络套接字的数据,则在获取数据之前无法继续。因此,一些文本随意使用术语阻塞作为“…阻塞I/O”或“…阻塞系统调用”。实际上,线程B相当沉睡。有一些特定的数据结构称为睡眠队列(sleep queues),很像机场上的豪华候机室。当操作系统检测到数据可用时,线程将被唤醒,就像候诊室的服务员一样。

主运行循环不是驱动应用程序的因素。我在MacOSX上,使用一个CVDisplayLink,它有效地产生了一个单独的(高优先级)线程,这将反过来驱动我的运行循环。据我所知,事件将在主线程上交付,因此同步似乎是有序的。那么被阻止或等待的区别到底是什么,它们是相同的吗?这很好地解释了这一点!谢谢我喜欢豪华的候机室。太生动了。