在分配的堆内存中,对于不同的偏移量是否需要互斥锁?

7
我正在为一个生成二进制数据表的工具搭建框架。计划使用多线程以充分利用我可用的24个核心。(我估计在单线程下生成数据的墙时将约为50天)。过去,我曾使用服务器/客户端设计和套接字通信来完成此任务,因为我需要将其分布在多台机器上。 这一次,我考虑采用单机/多线程方法,并试图找出正确的方法。 主线程将处理将任务分配给每个子线程并确定分配内存中的偏移量。 每个线程将写入分配内存中的唯一地址范围。由于这些块在记录之间永远不会重叠,因此没有两个线程将尝试写入相同的偏移量。

{Meta Data}{Rec1}{Rec2}{Rec3}{Rec4}{...}{...}{...}

void computeRecord(void *taskInput)
{
  struct TaskData *taskData = (TaskData *)(taskInput);

  RecordData data; 
  // A huge long computation block to populate data
  //   (4-5 second run time)

  long record_id = taskData->record_id;
  char *buffer   = taskData->start_buffer;

  // mutex lock needed here ??

  int n_bytes = sizeof(RecordData)
  memcpy( (char *)(buffer+record_id*n_bytes), (char *)(&recordData) n_bytes);

  // mutex unlock here ?
}

长篇设置。简短问题。在这种情况下,互斥锁是否必要?


1
我不认为这是必要的,但可能存在一些微妙之处,因此我不会回答。 - Iharob Al Asimi
3
我不希望一个需要50个计算天的任务完全存在内存中。这种计算:位数生成的水平应该很容易保存到磁盘上,而不会影响带宽,这使得可以轻松地收集部分运行,并将消费和生产分开。然而,对于你的问题,如果在大多数架构上你的偏移量合理对齐,就不需要互斥锁。 - Yakk - Adam Nevraumont
你有没有考虑使用OpenMP:它正是为解决这种并行性而设计的。 - Christophe
什么计算如此缓慢?只是好奇。 - Joonazan
@Yakk,如果我使用内存映射文件而不是堆上的内存,对我的原始问题的答案会改变吗? - MikeMayer67
显示剩余3条评论
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
5
为了获得最佳性能,您需要使数据与缓存行对齐 - 这将避免不同的CPU核心在彼此之间“反弹”缓存行。但是,无论如何,只要我们谈论相互独立的单个字节,就不需要任何保护措施。仅当多个线程访问完全相同的字节时才需要保护措施[当然,同时访问多个字节也适用]。 编辑:当然,前提是处理器具有字节寻址功能。我想到的处理器没有字节寻址功能是Alpha,但可能还有其他处理器。 (编辑2:不,对于符合C++11标准的编译器来说这并不重要,它取决于编译器以线程安全方式处理字节寻址)

你在断言没有处理器可以一次读写比一个字节更多的内存吗? - Yakk - Adam Nevraumont
2
在多线程程序中写入两个不同的地址是标准明确定义的。如果CPU无法进行字节寻址,则编译器必须考虑如何处理。否则,将无法编写正确的程序。 - Voo
@Voo:我认为这是两者兼而有之。如果数据完全独立,那么编译器就要负责。如果我们有一个非常大的字节数组,并且想要从多个线程向相邻(并且在同一机器字中)的字节写入数据,那么程序员就需要确保只有一个线程可以同时写入该区域。但对于x86和ARM,我确定这不是问题。 - Mats Petersson
@Mats 你是说如果你有 char[10] arr; 并且一个线程写入 arr[0] 和另一个线程写入 arr[1],那么标准会将其定义为未定义的行为?这完全违反了我对 C++ 标准如何定义数据竞争的理解。在我看来,arr[0]arr[1] 是两个独立的内存位置,是否有相关链接或者更好的标准语言来支持这一点呢? - Voo
2
目前的共识似乎是编译器负责确保对不同偏移量的写入被正确处理。主题上的问题 - Voo
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,