在 C 中的分叉进程之间共享锁定内存

问题描述

建立在 this answer 之上,我想制作一个程序,它可以将自己分叉到机器的 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]++;
}

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

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

解决方法

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

不,这不安全。至少你会得到不正确的结果,其中一些增量可能会被“丢弃”(因为另一个进程会在读取和写回增量值之间覆盖该值)。见Can num++ be atomic for 'int num'?

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

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

input_list = [[1,2],[3,4,5],4],5]]
result = [[1,4]]

但就此而言,如果您需要做的只是记录每个输出值被看到的总次数,则可以避免所有这些。只需让每个进程保留自己的private #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); } 数组,用于在这个进程中看到每个输出的次数,然后在最后将它们加在一起;加法毕竟是联想的。您可以让每个工作进程通过管道、或通过其自己唯一的共享内存段或各种其他简单方式将其结果发送回父进程。