你能否通过保证multithreading不能访问相同的内存来避免locking?
说我有一个大型的数组,我想用多个线程处理内容。 如果我将每个线程委托给一个特定的部分,保证没有重叠,这是否消除了任何locking的需要,假设线程不访问数组之外的任何其他内存?
像这样的东西(伪代码):
global array[9000000]; do_something(chunk) { for (i = chunk.start; i < chunk.end; i++) //do something with array } main() { chunk1 = {start: 0, end: 5000000}; chunk2 = {start: 5000000, end: 9000000}; start_thread(thread1, do_something(chunk1)); start_thread(thread2, do_something(chunk2)); wait_for_join(thread1); wait_for_join(thread2); //do something else with the altered array }
在符合C ++ 11的编译器中,这是安全的[intro.memory](§1.7):
存储器位置是标量types的对象或者具有非零宽度的相邻位域的最大序列。 […]两个执行线程(1.10)可以更新和访问单独的内存位置而不会相互干扰。
C11在§3.14中给出了相同的保证(他们甚至使用相同的措词)。
在C ++ 03编译器中,不能保证这个标准能够工作,但是如果编译器提供了类似的扩展保证,它仍然可以工作。
是的:如果你能保证没有两个线程访问同一个元素,那么就不需要进一步的同步。
如果两个线程在没有同步的情况下访问相同的内存位置(至less其中一个修改它),那么只有冲突(并且因此是潜在的数据竞争)。
(注意:这个答案是基于C ++ 11内存模型的,我刚刚注意到你也在问第二种语言,我相信C11指定了一个非常相似的内存模型,但是不能肯定地说答案也适用于C.对于这两种语言的老版本,线程安全是依赖于实现的。)
是的,你的确可以。
TCMalloc就是一个很好的例子。
是。
你甚至不需要保证没有两个线程访问相同的内存位置。 所有你需要保证的是没有一个线程修改任何另一个访问的位置(不pipe这是否意味着读或写)。
由于没有并发访问或者只读并发访问,所以你最好不要locking。
重要的性能问题!
对,你不需要显式的locking,因为正如别人所说的那样,没有共享内存的位置。
但是你可能会触发隐含的硬件同步 ,因为任意的块可能会导致caching行被共享(尽pipe在你的例子中使用的数字并不多)。 这被称为虚假分享 。
比如OpenMP等更高级的方法解决了这些问题:
- 块alignment(和线程号)根据底层硬件进行调整。
- 它提供了对线程池更好的控制,例如分摊线程实例的成本。
- 写起来更容易,而且干扰也更小。