Сообщения. Разделяемая память. Семафоры.

Выполнение

Программа работает из предыдущих. Также вместо работы с распределенной памятью System V напрямую (shmem), работа с памятью идет через mmap, то есть с проецированием файла в память. Это наиболее предппочтительный способ работы с распределенной памятью в современных ОС, тем более после завершения программы сегмент памяти созданный mmap будет удален.

Решение реализации следующее: клиент-сервер обащются с друг другом до тех пор пока не примут SIGINT. Для демонстрации в Докер-контейнере имеется скрипт, который позволяет программам общаться с друг другом 60 секунд, после чего посылает им SIGINT и выводит результаты общения, которые можно сравнить.

Инструкции по сборке

Сборка

cd labka6
docker build -t linux:labka6 .

Запуск

`docker run --rm linux:labka6

Готовый образ

docker pull elgudjo/linux:labka6
docker run --rm elgudjo/linux:labka6

Исходные файлы

server.c

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include <semaphore.h>


#define SHMOBJ_PATH         "/shmjeshu"

sem_t * sem_id;

/* message structure for messages in the shared segment */

struct shared_data {
    int var1;
    int var2;
};

void signal_callback_handler(int signum)
{

    /**
     * Semaphore unlink: Remove a named semaphore  from the system.
     */
    if ( shm_unlink("/mysem") < 0 )
    {
        perror("shm_unlink");
    }
    /**
     * Semaphore Close: Close a named semaphore
     */
    if ( sem_close(sem_id) < 0 )
    {
        perror("sem_close");
    }

    /**
     * Semaphore unlink: Remove a named semaphore  from the system.
     */
    if ( sem_unlink("/mysem") < 0 )
    {
        perror("sem_unlink");
    }

        // Terminate program
    exit(signum);
}


int main(int argc, char *argv[]) {
    int shmfd;
    int vol, cur;
    int shared_seg_size = (1 * sizeof(struct shared_data));   /* want shared segment capable of storing 1 message */
    struct shared_data *shared_msg;      /* the shared segment, and head of the messages list */

    signal(SIGINT, signal_callback_handler);

    /* creating the shared memory object    --  shm_open()  */
    shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
    if (shmfd < 0)
    {
        perror("In shm_open()");
        exit(1);
    }

    fprintf(stderr, "Created shared memory object %s\n", SHMOBJ_PATH);

    /* adjusting mapped file size (make room for the whole segment to map)      --  ftruncate() */
    ftruncate(shmfd, shared_seg_size);

    /**
     * Semaphore open
     */
    sem_id=sem_open("/mysem", O_CREAT, S_IRUSR | S_IWUSR, 1);

    /* requesting the shared segment    --  mmap() */
    shared_msg = (struct shared_data *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (shared_msg == NULL)
    {
        perror("In mmap()");
        exit(1);
    }
    fprintf(stderr, "Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);

    vol = 10;
    cur = 0;
    while(1)
    {
        sleep(2);
        printf("Waiting \n");
        sem_wait(sem_id);
        printf("Locked, About to sleep \n");
        shared_msg->var1 = vol;
        shared_msg->var2 = cur;
        printf("The var1 is %d \n",shared_msg->var1);
        printf("The var2 is %d \n",shared_msg->var2);
        sleep(3);
        sem_post(sem_id);
        printf("posting \n");
        vol++;
        cur++;
    }

    if (shm_unlink(SHMOBJ_PATH) != 0) {
        perror("In shm_unlink()");
        exit(1);
    }
    /**
     * Semaphore Close: Close a named semaphore
     */
    if ( sem_close(sem_id) < 0 )
    {
        perror("sem_close");
    }

    /**
     * Semaphore unlink: Remove a named semaphore  from the system.
     */
    if ( sem_unlink("/mysem") < 0 )
    {
        perror("sem_unlink");
    }

    return 0;
}

client.c

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include <semaphore.h>



#define SHMOBJ_PATH         "/shmjeshu"

sem_t * sem_id;

/* message structure for messages in the shared segment */

struct shared_data {
    int var1;
    int var2;
};

void signal_callback_handler(int signum)
{

    /**
     * Semaphore unlink: Remove a named semaphore  from the system.
     */
    if ( shm_unlink("/mysem") < 0 )
    {
        perror("shm_unlink");
    }

    /**
     * Semaphore Close: Close a named semaphore
     */
    if ( sem_close(sem_id) < 0 )
    {
        perror("sem_close");
    }

    /**
     * Semaphore unlink: Remove a named semaphore  from the system.
     */
    if ( sem_unlink("/mysem") < 0 )
    {
        perror("sem_unlink");
    }
        // Terminate program
    exit(signum);
}

int main(int argc, char *argv[]) {
    int shmfd;
    int shared_seg_size = (1 * sizeof(struct shared_data));   /* want shared segment capable of storing 1 message */
    struct shared_data *shared_msg;      /* the shared segment, and head of the messages list */


    signal(SIGINT, signal_callback_handler);

    /* creating the shared memory object    --  shm_open()  */
    shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
    if (shmfd < 0)
    {
        perror("In shm_open()");
        exit(1);
    }

    fprintf(stderr, "Created shared memory object %s\n", SHMOBJ_PATH);

    /* adjusting mapped file size (make room for the whole segment to map)      --  ftruncate() */
    ftruncate(shmfd, shared_seg_size);

    /**
     * Semaphore open
     */
    sem_id=sem_open("/mysem", O_CREAT, S_IRUSR | S_IWUSR, 1);


    /* requesting the shared segment    --  mmap() */
    shared_msg = (struct shared_data *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (shared_msg == NULL)
    {
        perror("In mmap()");
        exit(1);
    }
    fprintf(stderr, "Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);

    while(1)
    {
        sleep(2);
        printf("Waiting \n");
        sem_wait(sem_id);
        printf("Locked, About to sleep \n");
        printf("The var1 is %d \n",shared_msg->var1);
        printf("The var2 is %d \n",shared_msg->var2);
        sleep(2);
        sem_post(sem_id);
        printf("posting \n");
    }

    if (shm_unlink(SHMOBJ_PATH) != 0) {
        perror("In shm_unlink()");
    }
    exit(1);
    /**
     * Semaphore Close: Close a named semaphore
     */
    if ( sem_close(sem_id) < 0 )
    {
        perror("sem_close");
    }

    /**
     * Semaphore unlink: Remove a named semaphore  from the system.
     */
    if ( sem_unlink("/mysem") < 0 )
    {
        perror("sem_unlink");
    }

    return 0;
}

start.sh

#!/bin/bash
nohup shmemsemserver > server.txt &
nohup shmemsemclient > client.txt &
echo "Wait for 60 seconds"
sleep 60
#Interrupts latest processes with names specified
kill -INT $(pgrep -n shmemsemclient)
kill -INT $(pgrep -n shmemsemclient)
echo "Server work results"
cat server.txt
echo "Client work results"
cat client.txt

Makefile

PREFIX = /usr/local/bin
CC = clang
LIBS =  -lrt -lpthread
.PHONY: all clean install uninstall

all: shmemsemclient shmemsemserver
clean:
    rm -rf shmemsem{client,server} *.o
shmemsemserver.o: server.c
    $(CC)  -c -o shmemsemserver.o server.c $(LIBS)
shmemsemclient.o: client.c
    $(CC)  -c -o shmemsemclient.o client.c $(LIBS)
shmemsemclient: shmemsemclient.o
    $(CC)  -o shmemsemclient shmemsemclient.o $(LIBS)
shmemsemserver: shmemsemserver.o
    $(CC)  -o shmemsemserver shmemsemserver.o $(LIBS)
install:
    install -D shmemsemserver $(PREFIX)/shmemsemserver
    install -D shmemsemclient $(PREFIX)/shmemsemclient
uninstall:
    rm -rf $(PREFIX)/shmemsem{client,server}

Dockerfile

FROM debian:jessie-slim
#FROM alpine
WORKDIR /src
#RUN apk add --update clang binutils gcc clang-libs libc-dev coreutils
RUN apt-get update && apt-get install -y --no-install-recommends \
    libc6-dev clang coreutils binutils gcc make \
    && rm -rf /var/lib/apt/lists/*
ADD ./src/* ./
RUN make all
RUN make install
RUN cp start.sh /usr/local/bin/start.sh
RUN chmod 755 /usr/local/bin/start.sh
ENTRYPOINT ["start.sh"]

Скриншот

Screenshot