A Simple Client/Server Scenario

Idea: One Chunk Of Data, And A Mutex

  • Shared data …

    struct Data
    {
        struct pthread_mutex_t lock;
        char name[32];
        int value;
        int valid;
    };
    
  • Protected by a mutex ⟶ process shared

Server: Initialize Shared Data, Poll For Data

  • Open shared file

  • Truncate it to hold one struct Data item

  • mmap

  • Initialize valid flag

  • Initialize mutex ⟶ process shared

  • Loop: every second, see if valid (properly taking and releasing mutex)

#include "data.h"

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <cassert>


int main(int argc, char** argv)
{
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " FILENAME\n";
        return 1;
    }

    const char* filename = argv[1];
    int fd = open(filename, O_RDWR|O_CREAT|O_EXCL, 0666);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    int error = ftruncate(fd, sizeof(struct Data));    // <-- make room for struct Data
    if (error) {
        perror("ftruncate");
        return 1;
    }

    struct Data* data = (Data*)mmap(NULL, sizeof(struct Data), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

    data->valid = 0;                                   // <-- not valid, initially

    pthread_mutexattr_t mutex_attr;
    pthread_mutexattr_init(&mutex_attr);
    pthread_mutexattr_setpshared(&mutex_attr, 1);
    pthread_mutex_init(&data->lock, &mutex_attr);      // <-- put mutex in shared memory

    while (1) {
        struct Data consumed_data = {};
        int error = pthread_mutex_lock (&data->lock);
        assert(!error);
        {
            if (data->valid) {
                consumed_data = *data;
                data->valid = 0;
            }
        }
        error = pthread_mutex_unlock(&data->lock);
        assert(!error);

        if (consumed_data.valid)
            std::cout << consumed_data.name << ':' << consumed_data.value << std::endl;

        sleep(1);
    }
    
    munmap(data, sizeof(struct Data));
    return 0;
}

Client: Produce Data

  • Open file O_RDWR: need to lock mutex (otherwise write-only)

  • mmap

  • Put data into shared memory (properly taking and releasing mutex)

#include "data.h"

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
#include <string>
#include <cassert>


int main(int argc, char** argv)
{
    if (argc != 4) {
        std::cerr << "Usage: " << argv[0] << " FILENAME NAME VALUE\n";
        return 1;
    }

    const char* name = argv[2];
    if (strlen(name) > DATA_NAME_SIZE-1) {
        std::cerr << "Name too long (max. " << DATA_NAME_SIZE-1 << ')' << std::endl;
        return 1;
    }
    int value = std::stoi(argv[3]);

    const char* filename = argv[1];
    int fd = open(filename, O_RDWR);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    struct Data* data = (Data*)mmap(NULL, sizeof(struct Data), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

    int error = pthread_mutex_lock(&data->lock);
    assert(!error);
    {
        strcpy(data->name, name);
        data->value = value;
        data->valid = 1;
    }    
    pthread_mutex_unlock(&data->lock);

    munmap(data, sizeof(struct Data));
    return 0;
}