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

Lock memory shared between forked processes in 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]++;
}

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

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

Is the answer I linked to above safe if many processes try to increment the same entry in the count array at the same time?

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

If not, is there a way to make the processes use the array one at a time by asking them to lock it when it is free and wait when it is not free?

好吧,您可以在 C11 中使用 semaphore for the array, or one for each array element, which each process tries to decrement before accessing and increments afterwards; or even use the semaphore itself as the counter. (See Lock, mutex, semaphore... what's the difference? for more general info.) But this is expensive. A more efficient way is to use the atomic features,然后在您的数组上执行原子增量操作:

#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);
}

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