Попытка передать «указатель на структуру данных» обработчику сигнала с помощью функции sigqueue из одного процесса в другой, используя структуру siginfo_t

В настоящее время я изучаю сигналы на языке C в операционной системе Linux. У меня есть родительский процесс, который хочет отправить структуру целочисленных значений с именем struct Data дочернему процессу, который он развил, используя структуру siginfo_t, которая является параметром обработчика сигнала, когда мы определяем обработчик сигнала с помощью sigcation: void handler(int, siginfo_t*, void*)

родительский процесс определяет union sigval и устанавливает поле sival_ptr в объединении в значение (void*) data где данные — это struct Data, содержащий два целых числа. Затем родитель использует sigqueue(child_pid, SIGUSR1, my_sigval)

Дочерний процесс использует sigaction, как я упоминал ранее, и настраивает обработчик сигнала SIGUSR1 с помощью флага SA_SIGINFO.

Внутри обработчика сигнала в дочернем коде я определил указатель struct Data* data и выполните эту строку: data = (struct Data*) (si->si_value.sival_ptr) а затем я пытаюсь распечатать данные, которые я отправил от родителя.

Я получаю следующее: дочерний процесс завершается до того, как напечатает значения внутри struct Data data, и все, что находится до этой строки, выполняется и печатается на экране, как и ожидалось.

Где я неправ? разве я не передаю указатель на struct Data от родителя?

или я делаю что-то не так в процессе приведения внутри функции обработчика дочернего сигнала?

Вот коды:

Родитель:


#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

#define MY_SIGNAL SIGUSR1

// Define a structure to hold two integers
struct Data {
    int value1;
    int value2;
};

int main() {
    // Prepare data structure
    struct Data* data = (struct Data*) malloc(sizeof(struct Data));
    data->value1 = 10;
    data->value2 = 20;

    // Fork a child process
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork failed");
        return 1;
    } else if (pid == 0) { // Child process
        // Child process logic
        execlp("./c2","c2",  NULL);
                  //
    } else { // Parent process
        // Sending the signal with a pointer to the data structure
        union sigval value;
        value.sival_ptr = (void*) data;
//        value.sival_int = 7;
        sleep(1);
        sigqueue(pid, MY_SIGNAL, value);
        sleep(1);
    }

    wait(NULL);
    return 0;
}

ребенок:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define MY_SIGNAL SIGUSR1

// Define a structure to hold two integers
struct Data {
    int value1;
    int value2;
};

// Function to handle the signal
void handler(int sig, siginfo_t *si, void *unused) {
    printf("Received signal: %d\n", sig);
//    printf("Received signal value: %d\n", si->si_value.sival_int);
    struct Data* data;
    data = (struct Data*)(si->si_value.sival_ptr);
    printf("Received values: %d, %d\n", data->value1, data->value2);
    // Copy the received data into the allocated memory
}

int main() {
    // Set up signal handler
    struct sigaction sa;
    sa.sa_sigaction = handler;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    sigaction(MY_SIGNAL, &sa, NULL);

    
    pause();

    return 0;
}

(а) Передача указателя на данные в родительском процессе не может работать. Каждый процесс имеет свою собственную виртуальную память. Его данные находятся в его виртуальной памяти, а не в виртуальной памяти другого процесса, за исключением страниц памяти, которые предназначены для совместного использования между процессами. Если дочерний элемент получит адрес, то, что находится по этому адресу в его виртуальной памяти, будет отличаться от того, что находится по этому адресу в виртуальной памяти родителя. (б) Набор функций, которые можно вызывать в обработчике сигнала, очень ограничен, и printf среди них нет.

Eric Postpischil 16.04.2024 23:23

@EricPostpischil Спасибо, я подумал, что это так, сразу после публикации сообщения. Знаешь ли ты, как мне добиться того, чего я хочу?

Hamza Awashra 16.04.2024 23:29

Используйте правильный инструмент для работы. Вы мучаете sigqueue [и себя ;-)], пытаясь сделать то, что сообщения SysV IPC (msgsnd/msgrcv) уже делают лучше/чище. Пример см. в моем ответе: В C хранение данных в локальных переменных в потоках похоже на создание локальной копии? AKA Имеет ли смысл эта синхронизация Threadpool? Поскольку ваша структура данных небольшая, отправьте ее копию, а не указатель. Или вы можете отправить указатель, если используете общую память (shm* и/или mmap). Я с большим успехом использовал это в коммерческих продуктах R/T.

Craig Estey 17.04.2024 00:13

При использовании msgsnd/msgrcv после msgsnd получатель (выполняющий msgrcv) немедленно помечается как работоспособный. И, что более важно, системные вызовы вызывают немедленное перепланирование, поэтому приемник [скорее всего] запустится немедленно. Это сокращает задержку (время от выдачи msgsnd до момента возврата msgrcv).

Craig Estey 17.04.2024 00:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш план вряд ли сработает, поскольку указатели действительны только внутри процесса, поскольку каждый процесс имеет свое собственное адресное пространство.

Даже если у вас есть память, совместно используемая двумя процессами, блок может не быть найден по одному и тому же адресу в обоих процессах.


Поскольку здесь существуют отношения «родитель-потомок», вы можете настроить некоторую общую память перед разветвлением и использовать эту память для обмена данными. Убедитесь, что один процесс не может записывать в память одновременно с чтением, и наоборот.

Другие вопросы по теме