【问题标题】:In C, I want to access one array in two separate processes [duplicate]在 C 中,我想在两个单独的进程中访问一个数组 [重复]
【发布时间】:2023-12-28 12:14:01
【问题描述】:

这本质上是我想要做的,但输出是垃圾数据。我有哪些不同的选项可以使子数组在父进程内部可见?

#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    int foo[3];                                     //initialize array

    pid_t pid;
    pid = fork();                                   //create child thread

    if (pid == 0) {                                 //child:
        foo[0] = 0; foo[1] = 1; foo[2] = 2;         //populate array
    }

    else {                                          //parent:
        wait(NULL);                                 //wait for child to finish
        printf("%d %d %d", foo[0], foo[1], foo[2]); //print contents of array
    }

    return 0;
}

【问题讨论】:

  • 不不不。你想要这样做。
  • fork 不会创建一个单独的线程,它会创建一个单独的进程。子进程正在修改foo 副本(Linux 在fork 时实现了写时复制内存)。如果你真的想使用多个线程,请查找 pthreads。
  • 访问离开大声笑。孩子和父母都有自己的副本。你得到垃圾数据,因为父母从来没有费心向它的数组写入任何东西
  • 是的,我自己意识到,当我实际上在这里分叉进程时,我说的是“线程”。我本来打算问的是同样的问题,但关于线程。即便如此,为什么这样做是错误的?
  • 除了存在根本缺陷(参见 Stephen Newell 的评论)之外,您通常还需要协调锁定机制以避免内存损坏。

标签: c multithreading fork public


【解决方案1】:

使用mmap 你可以在你的父进程中创建一个共享内存块。这是一个为简洁起见删除错误检查的基本示例。

您希望确保为您的需要设置了适当的保护和标志。然后将mmap返回的地址交给你的子进程。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>

#define LIMIT_MAP 5

void child_worker(void *map)
{
    int map_value = -1;
    int idx = 0;

    while (map_value != LIMIT_MAP) {
        map_value = *((int *) map + (idx * sizeof(int)));
        printf("Map value: %d\n", map_value);
        idx++;
        sleep(2);
    }
}

int main(int argc, char *argv[])
{
    printf("Starting Parent Process...\n");

    long page_size = sysconf(_SC_PAGESIZE);

    void *memory_map = mmap(0, page_size, PROT_WRITE | PROT_READ, 
                                          MAP_SHARED | MAP_ANONYMOUS, 0, 0);

    printf("Memory map created: <%p>\n", memory_map);

    pid_t pid = fork();

    if (pid == 0) {
        sleep(1);
        printf("Starting child process\n");
        child_worker(memory_map);
        printf("Exiting child process...\n");
        return 0;

    } else {

        printf("Continuing in parent process\n");

        int set_values[5] = { 1, 2, 3, 4, 5 };

        for (int i=0; i < 5; i++) {
            printf("Setting value: %d\n", set_values[i]);
            *((int *) memory_map + (sizeof(int) * i)) = set_values[i];
            sleep(1);
        }

        waitpid(pid, NULL, 0);

        printf("Child process is finished!\n");
    }

    return 0;
}

如果fork 不是必需的并且您的平台允许,pthread 是一种选择。根据数组的操作方式,创建一个线程池,为每个工作线程传递数组的副本。

这是一个人为的例子,但也许你可以从中提取一些东西:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>

#define THREAD_COUNT 3
#define ITER_LIMIT   7

struct worker_params {
    int idx;
    int max;
    bool done;
    double *data;
    double condition;
};

void *worker(void *arg)
{
    struct worker_params *wp = (struct worker_params *) arg;

    int count = 0;

    while ( 1 ) {

        wp->data[wp->idx] = drand48();
        if (wp->max == count)
            wp->done = true;
        sleep(1);

        count++;
    } 

    return NULL;   
}

int main(int argc, char *argv[])
{
    double data[THREAD_COUNT] = { 0.0 };

    pthread_t worker_1, worker_2, worker_3;
    pthread_t worker_threads[] = { worker_1, worker_2, worker_3 };

    struct worker_params wps[] = {
        { .idx=0, .condition=0.1, .data=data, .done=0 },
        { .idx=1, .condition=0.2, .data=data, .done=0 },
        { .idx=2, .condition=0.3, .data=data, .done=0},
    };

    for (int i=0; i < THREAD_COUNT; i++) {
        wps[i].max = (rand() % ITER_LIMIT) + 2;
        pthread_create(&worker_threads[i], NULL, worker, (void *) &wps[i]);
    }

    // Continue on main execution thread

    int running = 1;

    while ( running ) {
        for (int i=0; i < THREAD_COUNT; i++) {
            if (wps[i].done) {
                printf("Limit hit in worker <%d>\n", i + 1);
                running = 0;
                break;
            }

            printf("Data in worker <%d> :: %g\n", i + 1, wps[i].data[i]);
        }

        sleep(1);
    }

    return 0;
}

【讨论】:

    最近更新 更多