首页 > 解决方案 > 锁定 C 中的分叉进程之间共享的内存

问题描述

这个答案的基础上,我想制作一个程序,它可以自行在机器的 CPU 上分配大量独立计算。计算输出集合 {0, ..., n - 1} 中的一个数字。我的目标只是计算大小为 n 的数组中每个输出的出现次数。

需要明确的是,每个子进程中的主循环如下所示:

for (i = start_range_for_this_process; i < end_range_for_this_process; i++)
{
    input = generate_input(i);
    output = the_computation(input);
    count[output]++;
}

我的问题如下:如果许多进程试图同时增加计数数组中的相同条目,我上面链接的答案是否安全?如果没有,有没有办法让进程一次使用一个数组,方法是要求它们在空闲时锁定它并在它不空闲时等待?

我尝试在网上搜索,但没有找到我要找的东西。我可能没有使用正确的关键字,因为我对并发编程不是很有经验。谢谢你的帮助!

标签: cconcurrencylockingforkshared-memory

解决方案


如果许多进程尝试同时增加计数数组中的相同条目,我链接到上面的答案是否安全?

不,这不安全。至少你会得到不正确的结果,其中一些增量可能会被“丢弃”(因为另一个进程在读取和写回增量值之间覆盖了该值)。请参阅“int num”的 num++ 是否是原子的?

如果没有,有没有办法让进程一次使用一个数组,方法是要求它们在空闲时锁定它并在它不空闲时等待?

好吧,您可以为数组设置一个信号量,或者为每个数组元素设置一个信号量,每个进程在访问之前尝试递减并在之后递增;甚至使用信号量本身作为计数器。(有关更一般的信息,请参阅Lock、mutex、semaphore...有什么区别?)但这很昂贵。更有效的方法是使用 C11 及更高版本中的原子特性对数组执行原子增量操作:

#include <stdatomic.h>
...
atomic_int *count = attach_shared_memory();
for (i = start_range_for_this_process; i < end_range_for_this_process; i++)
{
    input = generate_input(i);
    output = the_computation(input);
    atomic_fetch_add_explicit(&count[output], 1, memory_order_relaxed);
}

但就此而言,如果您需要做的只是计算每个输出值被看到的总次数,那么您可以避免所有这些。只需让每个进程保留自己的私有 count数组,以记录每个输出在进程中出现的次数,然后在最后将它们全部加在一起;毕竟,加法是关联的。您可以让每个工作进程通过管道或通过其自己独特的共享内存段或各种其他简单方式将其结果发送回父进程。


推荐阅读