multithreading 互斥锁:“阻塞”是什么意思?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3982501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 01:10:55  来源:igfitidea点击:

Mutex lock: what does "blocking" mean?

multithreadinglockingthread-safetymutexblocking

提问by zmippie

I've been reading up on multithreading and shared resources access and one of the many (for me) new concepts is the mutex lock. What I can't seem to find out is what is actually happening to the thread that finds a "critical section" is locked. It says in many places that the thread gets "blocked", but what does that mean? Is it suspended, and will it resume when the lock is lifted? Or will it try again in the next iteration of the "run loop"?

我一直在阅读多线程和共享资源访问,许多(对我来说)新概念之一是互斥锁。我似乎无法发现的是发现“临界区”被锁定的线程实际发生了什么。它在很多地方都说线程被“阻塞”了,但这意味着什么?是不是暂停了,解开锁会恢复吗?还是会在“运行循环”的下一次迭代中再次尝试?

The reason I ask, is because I want to have system supplied events (mouse, keyboard, etc.), which (apparantly) are delivered on the main thread, to be handled in a very specific part in the run loop of my secondary thread. So whatever event is delivered, I queue in my own datastructure. Obviously, the datastructure needs a mutex lock because it's being modified by both threads. The missing puzzle-piece is: what happens when an event gets delivered in a function on the main thread, I want to queue it, but the queue is locked? Will the main thread be suspended, or will it just jump over the locked section and go out of scope (losing the event)?

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

采纳答案by Jeremy W. Sherman

Blocked means execution gets stuck there; generally, the thread is put to sleep by the system and yields the processor to another thread. When a thread is blocked trying to acquire a mutex, execution resumes when the mutex is released, though the thread might block again if another thread grabs the mutex before it can.

阻塞意味着执行被卡在那里;通常,线程被系统置于睡眠状态并将处理器交给另一个线程。当一个线程在尝试获取互斥锁时被阻塞时,当互斥锁被释放时会恢复执行,但如果另一个线程抢先获取互斥锁,该线程可能会再次阻塞。

There is generally a try-lock operation that grab the mutex if possible, and if not, will return an error. But you are eventually going to have to move the current event into that queue. Also, if you delay moving the events to the thread where they are handled, the application will become unresponsive regardless.

通常有一个尝试锁定操作,如果可能的话,会抓取互斥锁,如果没有,则会返回错误。但是您最终将不得不将当前事件移动到该队列中。此外,如果您延迟将事件移动到处理它们的线程,应用程序无论如何都会变得无响应。

A queue is actually one case where you can get away with not using a mutex. For example, Mac OS X (and possibly also iOS) provides the OSAtomicEnqueue()and OSAtomicDequeue()functions (see man atomicor <libkern/OSAtomic.h>) that exploit processor-specific atomic operations to avoid using a lock.

队列实际上是一种情况,您可以不使用互斥锁。例如,Mac OS X(也可能还有 iOS)提供了OSAtomicEnqueue()OSAtomicDequeue()函数(参见man atomic<libkern/OSAtomic.h>),利用特定于处理器的原子操作来避免使用锁。

But, why not just process the events on the main thread as part of the main run loop?

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

回答by tvanfosson

The simplest way to think of it is that the blocked thread is put in a wait ("sleeping") state until the mutex is released by the thread holding it. At that point the operating system will "wake up" one of the threads waiting on the mutex and let it acquire it and continue. It's as if the OS simply puts the blocked thread on a shelf until it has the thing it needs to continue. Until the OS takes the thread off the shelf, it's not doing anything. The exact implementation -- which thread gets to go next, whether they all get woken up or they're queued -- will depend on your OS and what language/framework you are using.

最简单的思考方式是,被阻塞的线程被置于等待(“休眠”)状态,直到持有它的线程释放互斥锁。那时操作系统将“唤醒”等待互斥锁的线程之一,让它获取它并继续。就好像操作系统只是将被阻塞的线程放在一个架子上,直到它有它需要继续的东西。在操作系统将线程下架之前,它什么都不做。确切的实现——接下来要执行哪个线程,它们是全部被唤醒还是排队——将取决于您的操作系统以及您使用的语言/框架。

回答by ultimate cause

Too late to answer but I may facilitate the understanding. I am talking more from implementation perspective rather than theoretical texts.

回答太晚了,但我可能会促进理解。我更多地从实施的角度而不是理论文本进行讨论。

The word "blocking" is kind of technical homonym. People may use it for sleepingor mere waiting. The term has to be understood in context of usage.

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

Blocking means Waiting- Assume on an SMP system a thread B wants to acquire a spinlock held by some other thread A. One of the mechanisms is to disable preemption and keep spinning on the processor unless B gets it. Another mechanism probably, an efficient one, is to allow other threads to use processor, in case B does not gets it in easy attempts. Therefore we schedule out thread B (as preemption is enabled) and give processor to some other thread C. In this case thread B just waits in the scheduler's queue and comes back with its turn. Understand that B is not sleeping just waiting rather passively instead of busy-wait and burning processor cycles. On BSD and Solaris systems there are data-structures like turnstilesto implement this situation.

阻塞意味着等待- 假设在 SMP 系统上,线程 B 想要获取其他线程 A 持有的自旋锁。其中一种机制是禁用抢占并继续在处理器上旋转,除非 B 获得它。另一种机制可能是一种有效的机制,是允许其他线程使用处理器,以防 B 无法通过简单的尝试获得它。因此,我们调度线程 B(因为启用了抢占)并将处理器交给其他线程 C。在这种情况下,线程 B 只是在调度程序的队列中等待,然后轮到它回来。理解 B 不是在休眠,只是被动地等待,而不是忙等待和消耗处理器周期。在 BSD 和 Solaris 系统上,有像旋转门这样的数据结构来实现这种情况。

Blocking means Sleeping- If the thread B had instead made system call like read()waiting data from network socket, it cannot proceed until it gets it. Therefore, some texts casually use term blocking as "... blocked for I/O" or "... in blocking system call". Actually, thread B is rather sleeping. There are specific data-structures known as sleep queues- much like luxury waiting rooms on air-ports :-). The thread will be woken up when OS detects availability of data, much like an attendant of the waiting room.

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

回答by dty

Blocking means just that. It is blocked. It will not proceed until able. You don't say which language you're using, but most languages/libraries have lock objects where you can "attempt" to take the lock and then carry on and do something different depending on whether you succeeded or not.

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

But in, for example, Java synchronized blocks, your thread will stall until it is able to acquire the monitor (mutex, lock). The java.util.concurrent.locks.Lockinterface describes lock objects which have more flexibility in terms of lock acquisition.

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