Mutex 是否调用系统调用?
CRITICAL_SECTION 锁定(进入)和解锁(离开)是高效的,因为 CS 测试在用户空间中执行,无需进行内核系统调用 互斥体使得。解锁完全在用户空间中执行,而 ReleaseMutex 需要系统调用。
我刚刚在这本书中读到了这些句子。
内核系统调用是什么意思?你能给我这个函数的名字吗?
我是英语新手。我这样解释它们。
- CS 测试不使用系统调用。
- 互斥量测试使用系统调用。(但我不知道函数名称。请告诉我)
- CS 解锁不调用系统调用。
- 互斥体解锁需要系统调用。(但我不知道函数名。请告诉我)
另一个问题。
- 我认为 CRITICAL_SECTION 可能会调用 WaitForSingleObject 或系列函数。这些功能不需要系统调用吗?我想他们会的。所以CS测试不使用系统调用对我来说很奇怪。
CRITICAL_SECTION locking (enter) and unlocking (leave) are efficient because
CS testing is performed in user space without making the kernel system call that
a mutex makes. Unlocking is performed entirely in user space, whereas ReleaseMutex requires a system call.
I just read these sentences in this book.
What the kernel system call mean? Could you give me the function's name?
I'm a English newbie. I interpreted them like this.
- CS testing doesn't use a system call.
- Mutex testing uses a system call.(But I don't know the function name. Let me know)
- CS unlocking doesn't call a system call.
- Mutex unlocking requires a system call.(But I don't know the function name. Let me know)
Another question.
- I think CRITICAL_SECTION might call WaitForSingleObject or family functions. Don't these functions require a system call? I guess they do. So CS testing doesn't use a system call is very weird to me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
调用内核需要上下文切换,每次上下文切换都会对性能造成很小(但可测量)的影响。有问题的函数是ReleaseMutex() 本身。
临界区函数在
kernel32.dll
中可用(至少从调用者的角度来看 - 请参阅有关ntdll.dll
的讨论的注释),并且通常可以避免进行任何调用进入内核。值得注意的是,互斥对象可以同时从不同的进程访问。另一方面,
CRITICAL_SECTION
对象仅限于一个进程。Calling to the kernel requires a context switch, which is takes a small (but measurable) performance hit for every context switch. The function in question is
ReleaseMutex()
itself.The critical section functions are available in
kernel32.dll
(at least from the caller's point of view - see comments for discussion aboutntdll.dll
) and can often avoid making any calls into the kernel.It is worthwhile to know that Mutex objects can be accessed from different processes at the same time. On the other hand,
CRITICAL_SECTION
objects are limited to one process.据我所知,关键部分是使用信号量实现的。
临界区函数在 NTDLL 中实现,NTDLL 在用户模式下实现一些运行时函数,并将控制权传递给其他函数(系统调用)。 kernel32.dll 中的函数是简单的函数转发器。
另一方面,互斥锁是内核对象,因此需要系统调用。顺便说一句,内核称它们为“突变体”(不是开玩笑)。
To my knowledge critical sections are implemented using semaphores.
The critical section functions are implemented in NTDLL, which implements some runtime functions in user mode and passes control so the kernel for others (system call). The functions in kernel32.dll are simple function forwarders.
Mutexes on the other hand are kernel objects and require a system call as such. The kernel calls them "mutants", by the way (no joke).
仅当存在争用并且无法通过旋转缓解争用时,临界区才会调用转换到内核模式。在这种情况下,线程会阻塞并调用等待函数——这是一个系统调用。
Critical section calls only transition to kernel mode if there is contention and only then if they can't relieve the contention by spinning. In that case the thread blocks and calls a wait function – that's a system call.
Windows 中临界区的实现多年来发生了变化,但它始终是用户模式和内核调用的组合。
CRITICAL_SECTION 是一个包含用户模式更新值、内核模式对象(EVENT 或类似内容)的句柄以及调试信息的结构。
EnterCriticalSection 使用互锁的测试和设置操作来获取锁。如果成功,这就是所需要的全部(几乎,它还会更新所有者线程)。如果测试和设置操作无法获取,则会使用较长的路径,这通常需要使用
WaitForSignleObject
等待内核对象。如果使用InitializeCriticalSectionAndSpinCount
进行初始化,则EnterCriticalSection
可能会在用户模式下使用互锁操作进行重试以获取数据。下面是 Windows 7(64 位)中
EnterCriticalSection
的“快速”/无竞争路径的反汇编,其中包含一些内嵌注释因此,底线是,如果线程不需要阻塞,则它不会阻塞使用系统调用,只是一个互锁的测试和设置操作。如果需要阻塞,就会有系统调用。释放路径还使用互锁的测试和设置,并且如果其他线程被阻止,则可能需要系统调用。
将此与始终需要系统调用 NtWaitForSingleObject 和 NtReleaseMutant 的 Mutex 进行比较
The implementation of critical sections in Windows has changed over the years, but it has always been a combination of user-mode and kernel calls.
The CRITICAL_SECTION is a structure that contains a user-mode updated values, a handle to a kernel-mode object - EVENT or something like that, and debug information.
EnterCriticalSection uses an interlocked test-and-set operation to acquire the lock. If successful, this is all that is required (almost, it also updates the owner thread). If the test-and-set operation fails to aquire, a longer path is used which usually requires waiting on a kernel object with
WaitForSignleObject
. If you initialized withInitializeCriticalSectionAndSpinCount
thenEnterCriticalSection
may spin an retry to acquire using interlocked operation in user-mode.Below is a diassembly of the "fast" / uncontended path of
EnterCriticialSection
in Windows 7 (64-bit) with some comments inlineSo the bottom line is that if the thread does not need to block it will not use a system call, just an interlocked test-and-set operation. If blocking is required, there will be a system call. The release path also uses an interlocked test-and-set and may require a system call if other threads are blocked.
Compare this to Mutex which always requires a system call
NtWaitForSingleObject
andNtReleaseMutant