Обработка SIGINT с общей памятью и семафорами - PullRequest
1 голос
/ 12 января 2020

Я пытался написать программу с общей памятью и семафорами, которая работает до тех пор, пока не будет нажата Ctrl + C, т.е. получено SIGINT:

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

#define SHM_NAME "/shm"
#define SEM_1 "/sem_1"
#define SEM_2 "/sem_2"
#define SEM_3 "/sem_3"

static volatile sig_atomic_t run;

struct sharedMemory{
    int done;
};
static struct sharedMemory *shared;

static void handleSIGINT(int sig){
    if(sig == SIGINT){
       printf(" SIGINT caught: sig = %d\n", sig);
       shared->done = 1;
       run = 1;
    }
}

int main(int argc, char *argv[])
{
    // setup shared memory and semaphores
    int shmfd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0600);
    if (shmfd == -1){
        // handle error 
    }

    if (ftruncate(shmfd, sizeof(struct sharedMemory)) == -1){
        // handle error 
    }

    shared = mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (shared == MAP_FAILED){
       // close resources
    }

    sem_t *sem_read = sem_open(SEM_1, O_CREAT | O_EXCL, 0600, 0);
    sem_t *sem_write = sem_open(SEM_2, O_CREAT | O_EXCL, 0600, BUFFER_SIZE);
    // sem open error handling
    if (sem_read == SEM_FAILED)
       // close resources 

    if (sem_write == SEM_FAILED)
       // close resources 

    // settup signal handler
    signal(SIGINT, handleSIGINT);

    while (!run)
    {
        sem_wait(sem_read);

        // read from shared memory and store data or set shared->done to 1 to stop generator process

        sem_post(sem_write);
    }

    // close resources
    printf("exiting\n");
    exit(EXIT_SUCCESS);
}

Когда Ctrl + C нажата volatile run установлен на 1, и он выходит из l oop и выходит. Это прекрасно работает без разделяемой памяти и семафоров, но здесь я никогда не получаю строку exiting на stdout только SIGINT caught: sig = 2 и продолжает работать.

Почему?

1 Ответ

3 голосов
/ 12 января 2020

Причиной поведения, которое вы видите, является способ установки обработчика сигнала:

signal(SIGINT, handleSIGINT);

По умолчанию signal включает флаг SA_RESTART. Это означает, что sem_wait будет перезапущен после вызова обработчика сигнала.

Это одна из основных причин использования sigaction вместо signal. Измените приведенную выше строку на приведенный ниже код, и он должен работать так, как вам нужно.

struct sigaction saction;
saction.sa_handler = handleSIGINT;
sigemptyset(&saction.sa_mask);
saction.sa_flags = 0;
sigaction (SIGINT, &saction, NULL);

Не является частью вашего вопроса, но желательно также позвонить sem_unlink по SEM_1 и SEM_2 как проверить возвращаемые значения вызовов sem_open. Поскольку O_EXCL установлен в sem_open, произойдет сбой, если вы снова запустите программу после принудительного завершения предыдущего вызова с помощью kill.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...