0

This is essentially what I want to do, but the outputs are junk data. What are some of the different options I have for making the child's array visible from inside the parent process?

#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;
}
David S.
  • 11
  • 2
  • 3
    No no no. You ***DO NOT*** want to do this. – gsquaredxc Mar 28 '18 at 02:39
  • 3
    `fork` doesn't create a separate thread, it creates a separate process. The child process is modifying *its* copy of `foo` (linux implements copy-on-write memory when forking). If you really want to use multiple threads, look up pthreads. – Stephen Newell Mar 28 '18 at 02:45
  • 1
    Access away lol. Child and parent have their own copies. You get junk data because parent never bothered to write anything to it's array – smac89 Mar 28 '18 at 02:45
  • Yeah, I realized on my own that I said "threads" when I'm actually forking processes here. What I had intended to ask was the same question but in regards to threads. Even so, why is this wrong to do? – David S. Mar 28 '18 at 02:46
  • Aside from it being fundamentally flawed (see Stephen Newell's comment) you usually want to coordinate a locking mechanism to avoid memory corruption. – tijko Mar 29 '18 at 13:31

1 Answers1

0

Using mmap you can create a shared memory block in your parent process. This is a basic example removing error checking for brevity.

You want to sure the proper protections and flags are set for your needs. Then hand off the address returned by mmap to your child process.

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

If fork isn't a requirement and your platform allows for it, pthread is one option. Depending on how your array is being operated on, create a thread pool passing each worker thread a copy of your array.

This is a contrived example but maybe you can pull something from it:

#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;
}
tijko
  • 7,599
  • 11
  • 44
  • 64