使用多个互斥锁
我有一个大型树结构,多个线程同时在其上工作。理想情况下,我希望每个单元都有一个单独的互斥锁。
我查看了 bits/pthreadtypes.h
中 pthread_mutex_t
的定义,它相当短,因此在我的情况下,内存使用不应成为问题。
但是,当仅对 8 个线程使用许多(比如说几千个)不同的 pthread_mutex_t
时,是否会造成性能损失?
I have a large tree structure on which several threads are working at the same time. Ideally, I would like to have an individual mutex lock for each cell.
I looked at the definition of pthread_mutex_t
in bits/pthreadtypes.h
and it is fairly short, so the memory usage should not be an issue in my case.
However, is there any performance penalty when using many (let's say a few thousand) different pthread_mutex_t
s for only 8 threads?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您非常频繁地锁定和解锁,则可能会受到惩罚,因为获取和释放锁确实需要一些时间,并且如果锁存在争用,则可能会花费相当长的时间。
当在这样的结构中使用许多锁时,您必须非常具体地了解每个锁实际锁定的内容,并确保小心 AB-BA 死锁。例如,如果您在锁定操作期间更改树的结构,则需要以一致的顺序锁定将更改的所有节点,并确保处理后代的线程不会变得混乱。
如果您有大量的锁,分布在内存中,则缓存问题可能会导致性能问题(具体取决于体系结构),因为锁定操作通常会使缓存的至少某些部分失效。
您最好的选择可能是实现一个简单的锁定结构,然后对其进行分析,然后在必要时对其进行改进以提高性能。我不确定您正在对树做什么,但如果您希望读取的内容比更新的内容多得多,那么一个好的起点可能是整个树的单个读写器锁。
“我们应该忘记小效率,大约 97% 的情况下:过早的优化是万恶之源。”
——唐纳德·高德纳
If you are locking and unlocking very frequently, there can be a penalty, since obtaining and releasing locks does take some time, and can take a fair amount of time if the locks are contended.
When using many locks in a structure like this, you will have to be very specific about what each lock actually locks, and make sure you are careful of AB-BA deadlocks. For example, if you are changing the tree's structure during a locking operation, you will need to lock all the nodes that will be changed, in a consistent order, and make sure that threads working on descendants do not become confused.
If you have a very large number of locks, spread out across memory, caching issues could cause performance problems, depending on the architecture, as locking operations will generally invalidate at least some part of the cache.
Your best bet is probably to implement a simple locking structure, then profile it, then refine it to improve performance, if necessary. I'm not sure what you're doing with the tree, but a good place to start might be a single reader-writer lock for the whole tree, if you expect to read much more than you update.
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
-- Donald Knuth
需要说明您的锁定/访问模式,以便正确评估这一点。如果每个线程一次只持有一个或几个锁,并且任何两个或多个线程同时想要同一锁的概率很低(随机访问模式或圆形轨道上不同位置上的 8 个跑步者)以大致相同的速度运行或其他更复杂的事情)那么您将基本上避免最坏的情况,即线程必须休眠才能获得锁(或者在某些情况下必须让操作系统参与决定谁获胜),因为您有很少的线程和这么多的锁。
如果每个线程在任何时候都需要数百或数千个锁,那么事情就会开始发生变化。
我不会触及死锁避免,因为我对您正在使用的容器一无所知,但您需要意识到避免它们的必要性。
Your locking/access patterns need to be stated in order to properly evaluate this. If each thread would only hold one or a few locks at a time and the probability that any two or more threads would want the same lock at the same time is low (either a random access patter or 8 runners on different positions on a circular track running at roughly the same speed or other more complicated things) then you will mostly avoid the worst case where a thread has to sleep to get a lock (or in some cases have to get the OS involved to decide who wins) because you have so few threads and so many locks.
If each thread might want hundreds or thousands of locks at any one time then things will start to change.
I won't touch deadlock avoidance because I don't know anything about the container that you are using, but you need to be aware of the need to avoid them.