1

I have a homework assignment to write two programs, a producer and a consumer. The producer must take a positive integer as input from the user, preform a calculation on it (in this case, the Collatz conjecture), and store the result in shared memory. The consumer program must access this result and print it.

The issue is that I have been able to create, store, and print character arrays (using mmap and memcpy), but I cannot seem to do the same with integers or integer arrays, which is the type of data I would be producing with my calculations. I did also try storing my calculations as a character array, but was unable to convert the ints to chars.

Currently, the producer program just prints the results to the console instead of storing them.

Producer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main()
{
    /* The size (in bytes) of shared-memory object */
    const int SIZE = 4096;

    /* The name of shared-memory object */
    const char* Obj = "Shm";

    /* The shared-memory file descriptor */
    int shm_fd;

    /* The pointer to shared-memory object */
    void* ptr;

    /* Create the shared-memory object */
    shm_fd = shm_open(Obj, O_CREAT | O_RDWR, 0666);

    /* Configure the size of the shared-memory object */
    ftruncate(shm_fd, SIZE);

    /* Map the shared-memory object in the address space of the process */
    ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

    if (ptr == MAP_FAILED)
    {
        printf("Map failed\n");
        return -1;
    }


    //** NEW CODE //

    // calculate based on user input 
    int userInput; // variable to store user int input

    printf("please input a starting number for the collatz conjecture: \n");
    if (scanf("%d", &userInput) == 1) {
        // print each number in the conjecture 
        printf("%d", userInput);
        
        
        // TEST AREA 
    
        int input2 = 5; // THIS WORKS TO SAVE A STRING, BUT NOT INTS
        
        //char inputAr[SIZE];

        //char temp[] = (char)input2;
        //strcat(inputAr, temp);
        
        memcpy(ptr, &input2, SIZE);

        //  TEST AREA

        //char input[SIZE];
        //char temp[10];
        //strcpy(temp, "40123456");
        ////char temp[] = "4";
        //strcat(input, temp);
        //strcpy(temp, " 6");
        //strcat(input, temp);
        //memcpy(ptr, &input, SIZE);




        printf(" ");
        while (userInput != 1) {
            if (userInput % 2 == 0) {
                userInput = userInput / 2;
                printf("%d", userInput);
                printf(" ");
            }
            else {
                userInput = userInput * 3 + 1;
                printf("%d", userInput);
                printf(" ");
            }
        }// end while

    }

    //** END NEW CODE

    /* Create a message and write it to the shared-memory object */
    //printf("Please input a character string: \n");
    //fgets(ptr, SIZE, stdin);
    printf("Writing the message to the shared memory is done! \n");

    return 0;
}
Consumer
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main()
{

    /* The size (in bytes) of shared-memory object */
    const int SIZE = 4096;

    /* The name of shared-memory object */
    const char* Obj = "Shm";

    /* The shared-memory file descriptor */
    int shm_fd;

    /* The pointer to shared-memory object */
    void* ptr;

    /* Open the shared-memory object */
    shm_fd = shm_open(Obj, O_RDONLY, 0666);

    if (shm_fd == -1)
    {
        printf("Shared memory failed\n");
        exit(-1);
    }

    /* Map the shared-memory object in the address space of the process */
    ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);

    if (ptr == MAP_FAILED)
    {
        printf("Map failed\n");
        exit(-1);
    }

    
    /* Read from the shared-memory object */
    //printf("Test message: %d", (int*)ptr);
    printf("\n");
    printf("The message read from the shared memory: %s", (char*)ptr);
    

    /* Remove the shared-memory object */
    if (shm_unlink(Obj) == -1)
    {
        printf("Error removing %s\n", Obj);
        exit(-1);
    }

    return 0;
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
XanJo
  • 41
  • 6
  • 1
    What happens if you switch from `memcpy(ptr, &input2, SIZE);` to `memcpy(ptr, &input2, sizeof(int));` and to `printf("The message read from the shared memory: %d\n", *(int *)ptr);`? – David Ranieri Oct 19 '22 at 17:16
  • Thank you for your comment, that did allow me to save an int to shared memory and print it! – XanJo Oct 19 '22 at 17:41
  • 1
    You are welcome :) Note that you don't need to `memcpy`, see [Does mmap return aligned pointer values](https://stackoverflow.com/questions/42259495/does-mmap-return-aligned-pointer-values) - Simply: `*(int *)ptr = input2;`, or better yet, with another pointer: `int *array = ptr;` you can use the array subscript operator: `array[0] = input2;` – David Ranieri Oct 19 '22 at 18:04
  • oh, that's really good to know! That should make it a lot easier to store an array with the outcome of each step in the conjecture. By the way, I did notice that once I made the changes that allowed me to store an int, the shm_unlink is no longer removing the shared memory object. Do you have any idea why that might be? – XanJo Oct 19 '22 at 18:11
  • No idea, the change should not affect that part of the code at all. – David Ranieri Oct 19 '22 at 18:44

1 Answers1

4

Single Integer

Remember that in the producer program you have stored the integer input2 inside the shared memory, so you need to print it out as an integer, not as a character array. Instead of

printf("The message read from the shared memory: %s", (char *)ptr);

you need to write it as

int *integer_array = (int *) ptr;
printf("The message read from the shared memory: %d", *integer_array);

This casts ptr (which is a void *) type into an integer pointer (int *), which you can dereference to get the value of input2. Additionally, "%d" is used for integers instead of "%s".

Integer Array

To print out an array of integers, not just a single one, you'd have to have enough space in ptr for number_of_ints * sizeof(int). In each Collatz conjecture iteration, you just store the result in the array like so:

int *integer_array = (int *) ptr;
while (userInput != 1) {
    if (userInput % 2 == 0) {
        userInput = userInput / 2;
    } else {
        userInput = userInput * 3 + 1;
    }

    *(integer_array++) = userInput;
}

Once the producer program has finished, the consumer program can print each of these numbers out like this:

int *integer_array = (int *) ptr;
for (int i = 0; i < number_of_ints; i++) {
    printf("%d ", integer_array[i]);
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
tsoa
  • 131
  • 7
  • Hey, this was really helpful, thank you for taking the time to post it! I'm wondering if you have any idea how I can determine the number of elements in the array in the producer program? I tried using `int number_of_elements = sizeof(integer_array)/sizeof(integer_array[0])` and it does not return the correct number of elements. – XanJo Oct 19 '22 at 21:08
  • 1
    Hi, the only way I can think of is performing the Collatz conjecture two times; once to figure out how many elements you need in your array, and the second to find the results and store them in the array. I am not sure, but there may be a way to remap every time you want to add an element, allowing you to perform the Collatz conjecture once, but it's probably less efficient than just doing it twice without remapping. – tsoa Oct 19 '22 at 21:27
  • That's actually a pretty good idea. I ended up just adding a 0 as the last element in the array, then moving through the array and increasing a count variable until I reached a value == 0. Not an elegant solution, but it works in this case. – XanJo Oct 20 '22 at 00:00