Правильно ли отправлять сигналы от дочерних процессов и получать таким образом в родительском? - PullRequest
0 голосов
/ 29 декабря 2018

Моя задача - иметь несколько детей и родителей, которые общаются друг с другом.Я читаю задачи из файла, и создание дочерних элементов зависит от количества задач.В родительском я отправляю задания разным детям.Таким образом, ребенок может «работать» над задачей.У каждого ребенка есть своя труба.После того, как ребенок получил данные и выполнил некоторую работу, он должен послать сигнал своему родителю, а чуть позже через его канал послать сообщение о том, что «я сегодня закончил».Я не уверен, как справиться с получением нескольких сигналов.Как мне этого добиться?

Код:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>

#define MAX_PROCESS 10
const char *defaultPipe = "/tmp/child";
static int orderNum = 0;
static int workerNum = 0;
static pid_t shutDown[MAX_PROCESS];
static char pipes[MAX_PROCESS][100];

typedef struct Order
{
    int id;
    char created[256];
    char fullName[256];
    char email[256];
    char phone[256];
    char status;
    int performance;
    int days;
    struct Order *next;
} Order;

typedef struct Order *node;

void startJob();
void sendPriorityJobs(node priorityHead);
void handler(int signo, siginfo_t *info, void *context);
void createWorker(node orderA, int workerID);

node createNode();
node createOrder(char *fullName, char *email, char *phone, char *created, int performance);

int main()
{
    //char msgFromWorker[256];

    struct sigaction sa;
    sa.sa_handler = (void *)handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGUSR2, &sa, NULL);

    node test1 = createOrder("Jane Doe", "test1@gmail.com", "12345678", "2018-12-25 8:00", 1000);
    node test2 = createOrder("John Doe", "test2@gmail.com", "87654321", "2018-12-25 9:00", 1001);
    test1->next = test2;

    printf("Parent pid: %d\n", getpid());

    /*This is where we send the task */
    sendPriorityJobs(test1);

    int i;
    for (i = 0; i < workerNum; i++)
    {
        /*int p = open(pipes[i], O_RDONLY);
        read(p, msgFromWorker, sizeof(msgFromWorker));
        sleep(1);
        printf("%s\n", msgFromWorker);
        close(p);*/
        waitpid(shutDown[i], NULL, 0);
    }

    return 0;
}

void createWorker(node orderA, int workerID)
{
    int parent; // child;
    pid_t worker;
    char strID[12];
    sprintf(strID, "%d", workerID);
    char pipe[100];
    strcpy(pipe, defaultPipe);
    strcat(pipe, strID);
    mkfifo(pipe, S_IRUSR | S_IWUSR);

    worker = fork();

    if (worker == 0)
    {

        //this is a temporarily variable for the received structure.(order)
        node order_A = createNode();

        parent = open(pipe, O_RDONLY);
        int ret;
        if ((ret = read(parent, &order_A, sizeof(Order))) > 0)
        {
            printf("[Child %d]: started work on %d. order.\n", getpid(), order_A->id);
            //printf("ret: %d\n", ret);
            //printf("%d,%s,%s,%s,%s,%d\n", order_A->id,order_A->fullName,order_A->email,order_A->phone,order_A->created,order_A->performance);
        }

        startJob();

        char endMessage[256];
        sprintf(endMessage, "[Child %d]: ended his daily task.", getpid());

        /*Sending the done message via pipe. This is questionable part, 
        how to do this properly. */
        /*child = open(pipe, O_WRONLY);
        write(child, &endMessage, strlen(endMessage) + 1);*/

        free(order_A);
        exit(0);
    }
    else
    {
        //Save the child's pid
        shutDown[workerID] = worker;

        //Save the child's pipe name.
        strcpy(pipes[workerID], pipe);

        parent = open(pipe, O_WRONLY);
        int ret;
        if ((ret = write(parent, &orderA, sizeof(Order))) > 0)
        {
            printf("[Parent]: sending %d. order!\n", orderA->id);
            //printf("ret: %d\n", ret);
        }
        close(parent);
    }
}

void startJob()
{
    pid_t parentPID = getppid();
    sleep(2);
    printf("[Child %d]: is done, sending signal.\n", getpid());
    kill(parentPID, SIGUSR2);
}

void sendPriorityJobs(node priorityHead)
{
    node current = priorityHead;
    while (current != NULL)
    {
        createWorker(current, workerNum);
        workerNum++;
        current = current->next;
    }
}

node createNode()
{
    node tmp;
    tmp = (node)malloc(sizeof(struct Order));
    tmp->next = NULL;
    return tmp;
}

node createOrder(char *fullName, char *email, char *phone, char *created, int performance)
{
    node newOrder;
    newOrder = createNode();

    strcpy(newOrder->fullName, fullName);
    strcpy(newOrder->email, email);
    strcpy(newOrder->phone, phone);
    strcpy(newOrder->created, created);
    newOrder->performance = performance;
    newOrder->status = 'N';
    newOrder->id = orderNum + 1;
    orderNum++;

    return newOrder;
}

void handler(int signo, siginfo_t *info, void *context)
{
    char msg[256];
    time_t t;
    time(&t);
    sprintf(msg, "[Parent]: i got the signal(%d) from [Child %d] time: %s", signo, info->si_pid, ctime(&t));
    write(1, msg, strlen(msg) + 1);
}

Я не уверен, как отправить несколько сигналов и сообщения о конце дня и получить их в родительском.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

В основном, большинство случаев @ код Джонатана Леффлера работает, но когда система получает два сигнала одновременно, она вообще не будет работать, и вы не сможете получить второй сигнал.Чтобы решить эту проблему, я использовал сигнал в реальном времени вместо SIGUSR1 | 2.

0 голосов
/ 31 декабря 2018

В некоторой степени перефразирование пунктов, сделанных в комментарии к вопросу, не исключая сеанс чата , содержит ответ в нескольких частях.

Терминология

Этокак правило, лучше всего зарезервировать термин «каналы» для типа канала, созданного системным вызовом pipe() (или функцией, заключающей в себе системный вызов), используя термин FIFO для «именованных каналов», созданныхmkfifo() системный вызов.Обратите внимание, что вы не можете открывать каналы с помощью системного вызова open();вы не можете открыть FIFO, кроме как с помощью open() или его второстепенного варианта openat().

Кроме того, см. Является ли хорошей идеей вводить указатели на определения типа? , на который краткий ответвообще "нет".Это вызвало некоторую путаницу в вашем коде, где у вас есть:

if ((ret = write(parent, &orderA, sizeof(Order))) > 0)

if ((ret = read(parent, &order_A, sizeof(Order))) > 0)

В обоих случаях переменная является указателем на Order (a node) и дополнительной косвенной ссылкой на & неверно, потому что sizeof(Order *) != sizeof(Order) - и вы отправляете неверные данные по конвейеру и читаете в неправильном месте.Вероятность путаницы была бы меньше, если бы у вас было typedef struct Order Order;, а переменные имели тип Order *.

Версия 1

В какой-то момент обсуждения я отправил следующее (с ошибками)код.Удивительно, но это сработало более или менее.Но это было в основном случайно, не в последнюю очередь из-за показанных проблем чтения / записи.

Этот код использует библиотечную функцию, доступную в моем репозитории SOQ (вопросы о переполнении стека) на GitHub в виде файловstderr.c и stderr.h в подкаталоге src / libsoq .

Дефектный код - не используйте

/* SO 5396-9266 */
#include "posixver.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include "stderr.h"

#define MAX_PROCESS 10
const char *defaultPipe = "/tmp/child";
static int orderNum = 0;
static int workerNum = 0;
static pid_t shutDown[MAX_PROCESS];
static char pipes[MAX_PROCESS][100];

typedef struct Order
{
    int id;
    char created[256];
    char fullName[256];
    char email[256];
    char phone[256];
    char status;
    int performance;
    int days;
    struct Order *next;
} Order;

typedef struct Order *node;

void startJob(void);
void sendPriorityJobs(node priorityHead);
void handler(int signo, siginfo_t *info, void *context);
void createWorker(node orderA, int workerID);

node createNode(void);
node createOrder(char *fullName, char *email, char *phone, char *created, int performance);

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    if (argc != 1)
        err_usage("");
    err_setlogopts(ERR_PID|ERR_MILLI);

    struct sigaction sa;
    sa.sa_handler = (void *)handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    sigaction(SIGUSR2, &sa, NULL);

    node test1 = createOrder("Jane Doe", "test1@gmail.com", "12345678", "2018-12-25 8:00", 1000);
    node test2 = createOrder("John Doe", "test2@gmail.com", "87654321", "2018-12-25 9:00", 1001);
    test1->next = test2;

    printf("Parent pid: %d\n", getpid());

    /*This is where we send the task */
    sendPriorityJobs(test1);

    for (int i = 0; i < workerNum; i++)
    {
        /*int p = open(pipes[i], O_RDONLY);
        read(p, msgFromWorker, sizeof(msgFromWorker));
        sleep(1);
        printf("%s\n", msgFromWorker);
        close(p);*/
        int status;
        int corpse = waitpid(shutDown[i], &status, 0);
        if (corpse < 0)
            err_sysrem("child %d - no status available: ", shutDown[i]);
        else
            err_remark("child %d (corpse %d) exited with status 0x%.4X\n", shutDown[i], corpse, status);
    }
    err_remark("All done!\n");

    return 0;
}

static void dump_order(const char *tag, const node order)
{
    err_remark("%s (%p):\n", tag, (void *)order);
    err_remark("Order: %d, %s, %s, %s, %s, %d\n", order->id, order->fullName,
               order->email, order->phone, order->created, order->performance);
}

void createWorker(node orderA, int workerID)
{
    int parent; // child;
    pid_t worker;
    char strID[12];
    sprintf(strID, "%d", workerID);
    char pipe[100];
    strcpy(pipe, defaultPipe);
    strcat(pipe, strID);
    if (mkfifo(pipe, S_IRUSR | S_IWUSR) != 0)
        err_syserr("failed to create FIFO '%s': ", pipe);
    err_remark("FIFO %s created\n", pipe);

    worker = fork();
    if (worker < 0)
        err_syserr("failed to fork: ");

    if (worker == 0)
    {
        err_remark("worker at play!\n");
        //this is a temporarily variable for the received structure.(order)
        node order_A = createNode();

        parent = open(pipe, O_RDONLY);
        if (parent < 0)
            err_syserr("failed to open FIFO '%s' for reading: ", pipe);
        int ret;
        if ((ret = read(parent, order_A, sizeof(Order))) > 0)
        {
            printf("[Child %d]: started work on %d. order.\n", getpid(), order_A->id);
            //printf("ret: %d\n", ret);
            //printf("%d,%s,%s,%s,%s,%d\n", order_A->id,order_A->fullName,order_A->email,order_A->phone,order_A->created,order_A->performance);
            dump_order("Read by child:", order_A);
        }

        startJob();

        char endMessage[256];
        sprintf(endMessage, "[Child %d]: ended his daily task.", getpid());

        /*Sending the done message via pipe. This is questionable part, 
        how to do this properly. */
        /*child = open(pipe, O_WRONLY);
        write(child, &endMessage, strlen(endMessage) + 1);*/

        err_remark("Message to parent: %s\n", endMessage);
        free(order_A);
        exit(0);
    }
    else
    {
        //Save the child's pid
        shutDown[workerID] = worker;

        //Save the child's pipe name.
        strcpy(pipes[workerID], pipe);

        parent = open(pipe, O_WRONLY);
        int ret;
        if ((ret = write(parent, &orderA, sizeof(Order))) > 0)   // BUG!
        {
            printf("[Parent]: sending %d. order!\n", orderA->id);
            dump_order("Parent sends", orderA);
            //printf("ret: %d\n", ret);
        }
        else
            err_syserr("faileds to writ to child %d\n", (int)worker);  // Ick!
        close(parent);
    }
}

void startJob(void)
{
    pid_t parentPID = getppid();
    sleep(1);
    printf("[Child %d]: is done, sending signal.\n", getpid());
    if (kill(parentPID, SIGUSR2) != 0)
        err_syserr("failed to signal parent process %d\n", (int)parentPID);
    else
        err_remark("signalled parent process %d with SIGUSR2\n", (int)parentPID);
}

void sendPriorityJobs(node priorityHead)
{
    node current = priorityHead;
    while (current != NULL)
    {
        createWorker(current, workerNum);
        workerNum++;
        current = current->next;
    }
    err_remark("All priority jobs sent\n");
}

node createNode(void)
{
    node tmp;
    tmp = (node)malloc(sizeof(struct Order));
    tmp->next = NULL;
    return tmp;
}

node createOrder(char *fullName, char *email, char *phone, char *created, int performance)
{
    node newOrder;
    newOrder = createNode();

    strcpy(newOrder->fullName, fullName);
    strcpy(newOrder->email, email);
    strcpy(newOrder->phone, phone);
    strcpy(newOrder->created, created);
    newOrder->performance = performance;
    newOrder->status = 'N';
    newOrder->id = orderNum + 1;
    orderNum++;

    return newOrder;
}

void handler(int signo, siginfo_t *info, void *context)
{
    (void)context;  // Unused
    char msg[256];
    time_t t;
    time(&t);
    sprintf(msg, "[Parent]: i got the signal(%d) from [Child %d] time: %s", signo, info->si_pid, ctime(&t));
    err_remark("%s: %d from %d\n", __func__, signo, info->si_pid);
    int nbytes = strlen(msg) + 1;
    int obytes;
    if ((obytes = write(1, msg, nbytes)) != nbytes)
        err_syserr("short write %d bytes (%d expected): ", obytes, nbytes);
    err_remark("return from %s\n", __func__);
}

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

Пример выполнения

Parent pid: 89291
signal67: 2018-12-30 15:54:17.298 - pid=89291: FIFO /tmp/child0 created
signal67: 2018-12-30 15:54:17.299 - pid=89292: worker at play!
[Parent]: sending 1. order!
[Child 89292]: started work on 2088763392. order.
signal67: 2018-12-30 15:54:17.299 - pid=89291: Parent sends (0x7fba7c800000):
signal67: 2018-12-30 15:54:17.299 - pid=89291: Order: 1, Jane Doe, test1@gmail.com, 12345678, 2018-12-25 8:00, 1000
signal67: 2018-12-30 15:54:17.299 - pid=89291: FIFO /tmp/child1 created
signal67: 2018-12-30 15:54:17.299 - pid=89292: Read by child: (0x7fba7d001800):
signal67: 2018-12-30 15:54:17.300 - pid=89292: Order: 2088763392, , ?, ?, ?, -413540392
signal67: 2018-12-30 15:54:17.300 - pid=89293: worker at play!
[Parent]: sending 2. order!
signal67: 2018-12-30 15:54:17.300 - pid=89291: Parent sends (0x7fba7c801000):
signal67: 2018-12-30 15:54:17.300 - pid=89291: Order: 2, John Doe, test2@gmail.com, 87654321, 2018-12-25 9:00, 1001
[Child 89293]: started work on 2088767488. order.
signal67: 2018-12-30 15:54:17.300 - pid=89291: All priority jobs sent
signal67: 2018-12-30 15:54:17.300 - pid=89293: Read by child: (0x7fba7d001800):
signal67: 2018-12-30 15:54:17.300 - pid=89293: Order: 2088767488, , ?, ?, ?, -413540392
[Child 89292]: is done, sending signal.
signal67: 2018-12-30 15:54:18.301 - pid=89291: handler: 31 from 89292
[Parent]: i got the signal(31) from [Child 89292] time: Sun Dec 30 15:54:18 2018
signal67: 2018-12-30 15:54:18.301 - pid=89291: return from handler
signal67: 2018-12-30 15:54:18.300 - pid=89292: signalled parent process 89291 with SIGUSR2
[Child 89293]: is done, sending signal.
signal67: 2018-12-30 15:54:18.301 - pid=89291: handler: 31 from 89293
[Parent]: i got the signal(31) from [Child 89293] time: Sun Dec 30 15:54:18 2018
signal67: 2018-12-30 15:54:18.301 - pid=89291: return from handler
signal67: 2018-12-30 15:54:18.301 - pid=89292: Message to parent: [Child 89292]: ended his daily task.
signal67: 2018-12-30 15:54:18.301 - pid=89293: signalled parent process 89291 with SIGUSR2
signal67: 2018-12-30 15:54:18.301 - pid=89293: Message to parent: [Child 89293]: ended his daily task.
signal67: 2018-12-30 15:54:18.302 - pid=89291: child 89292 (corpse 89292) exited with status 0x0000
signal67: 2018-12-30 15:54:18.302 - pid=89291: child 89293 (corpse 89293) exited with status 0x0000
signal67: 2018-12-30 15:54:18.302 - pid=89291: All done!

Вы можете увидеть мусорв дамп информации полученной от родителя.Однако это показывает, что флаг SA_RESTART важен в вызове sigaction().Без этого функция waitpid() возвращает ошибки, которые эта программа отлавливает и сообщает.

Версия 2

Это в основном рабочий код, который на самом деле использует sigsuspend() Цикл примерно такой же, как в предыдущем воплощении вашего кода.Однако это несколько иное.В частности, это возвращает информацию от детей.Это делается с использованием того же FIFO, который использовался для передачи информации от родителя к детям.Родитель сначала открывает FIFO для записи, затем пишет сообщение дочернему элементу, а затем закрывает FIFO.Тем временем ребенок открывает FIFO для чтения, читает сообщение, а затем закрывает FIFO.Когда все дочерние элементы дали сигнал родителю (используя цикл sigsuspend), он считывает ответы, тогда как дочерние элементы открывают FIFO для записи, записи и закрытия FIFO, в то время как родительский элемент открывает FIFO для чтения, читает ответи снова закрывает FIFO.Только после этого родитель зацикливается на ожидании смерти своих детей (многопроцессная работа в Unix-подобных системах - болезненное дело, как и с мертвыми детьми, зомби и всеми остальными).

Этот кодтакже удаляет FIFO как до, так и после его запуска.Имена FIFO в каталоге /tmp легко вывести, и, следовательно, легко сломать программу (например, создать каталог /tmp/child.0).Лучшее решение будет использовать mkstemp() или аналогичную функцию для создания имен FIFO (отмечая, что mkstemp() фактически создает файл, а не FIFO; не существует прямого механизма для создания уникальнос именем FIFO, о котором я знаю).

Используемый код, но все еще не полированный

/* SO 5396-9266 */
#include "posixver.h"
#include "stderr.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#define MAX_PROCESS 10

static const char defaultPipe[] = "/tmp/child.";
static int orderNum = 0;
static int workerNum = 0;
static pid_t shutDown[MAX_PROCESS];
static char pipes[MAX_PROCESS][100];

struct SigCaught
{
    int             sig_number;
    struct timespec sig_tstamp;
    int             sig_sender;
    void           *sig_contxt;
};

static struct SigCaught sig_list[MAX_PROCESS];
static int sig_cur = 0;
static int sig_prt = 0;

typedef struct Order
{
    int id;
    char created[256];
    char fullName[256];
    char email[256];
    char phone[256];
    char status;
    int performance;
    int days;
    struct Order *next;
} Order;

typedef struct Order *node;

static void startJob(void);
static void sendPriorityJobs(node priorityHead);
static void sig_handler(int signo, siginfo_t *info, void *context);
static void sig_printer(void);
static void createWorker(node orderA, int workerID);
static node createNode(void);
static node createOrder(char *fullName, char *email, char *phone, char *created, int performance);
static void get_response(void);

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    if (argc != 1)
        err_usage("");
    err_setlogopts(ERR_PID|ERR_MILLI);

    struct sigaction sa;
    sa.sa_handler = (void *)sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    sigaction(SIGUSR2, &sa, NULL);

    node test1 = createOrder("Jane Doe", "test1@gmail.com", "12345678", "2018-12-25 8:00", 1000);
    node test2 = createOrder("John Doe", "test2@gmail.com", "87654321", "2018-12-25 9:00", 1001);
    test1->next = test2;

    printf("Parent pid: %d\n", getpid());

    /* This is where we send the task */
    sendPriorityJobs(test1);

    for (int i = 0; i < workerNum; i++)
    {
        sigset_t es;
        sigemptyset(&es);
        err_remark("suspending...\n");
        sigsuspend(&es);
        err_remark("awake again.\n");
    }

    sig_printer();
    get_response();

    /* Wait for child processes to signal, write, and exit */
    for (int i = 0; i < workerNum; i++)
    {
        int status;
        int corpse = waitpid(shutDown[i], &status, 0);
        if (corpse > 0)
            err_remark("child %d (corpse %d) exited with status 0x%.4X\n", shutDown[i], corpse, status);
        else
            err_sysrem("child %d - no status available: ", shutDown[i]);
    }
    err_remark("All done!\n");

    /* Clean up FIFOs */
    for (int i = 0; i < workerNum; i++)
        unlink(pipes[i]);

    return 0;
}

static void dump_order(const char *tag, const node order)
{
    err_remark("%s (%p):\n", tag, (void *)order);
    err_remark("Order: %d, %s, %s, %s, %s, %d\n", order->id, order->fullName,
               order->email, order->phone, order->created, order->performance);
}

void createWorker(node orderA, int workerID)
{
    int parent;
    pid_t worker;
    char strID[12];
    sprintf(strID, "%d", workerID);
    char pipe[100];
    strcpy(pipe, defaultPipe);
    strcat(pipe, strID);
    if (unlink(pipe) != 0 && errno != ENOENT)
        err_syserr("failed to remove FIFO '%s': ", pipe);
    if (mkfifo(pipe, S_IRUSR | S_IWUSR) != 0)
        err_syserr("failed to create FIFO '%s': ", pipe);
    err_remark("FIFO %s created\n", pipe);

    worker = fork();
    if (worker < 0)
        err_syserr("failed to fork: ");

    if (worker == 0)
    {
        err_remark("worker at play!\n");
        node order_A = createNode();

        parent = open(pipe, O_RDONLY);
        if (parent < 0)
            err_syserr("failed to open FIFO '%s' for reading: ", pipe);
        int ret;
        if ((ret = read(parent, order_A, sizeof(Order))) != sizeof(Order))
            err_syserr("short read of %d bytes (%zu expected) from parent: ", ret, sizeof(Order));
        printf("[Child %d]: started work on %d. order.\n", getpid(), order_A->id);
        dump_order("Read by child:", order_A);
        close(parent);

        startJob();     /* Signal to parent */

        char endMessage[256];
        sprintf(endMessage, "[Child %d]: ended his daily task.", getpid());

        parent = open(pipe, O_WRONLY);
        if (parent < 0)
            err_syserr("failed to open FIFO '%s' for writing: ", pipe);
        err_remark("successfully reopened FIFO '%s' for writing\n", pipe);

        int len = strlen(endMessage);
        if (write(parent, endMessage, len) != len)
            err_syserr("faied to write message of %d bytes to parent: ", len);
        close(parent);

        err_remark("Message sent to parent: %s\n", endMessage);
        free(order_A);
        exit(0);
    }
    else
    {
        shutDown[workerID] = worker;
        strcpy(pipes[workerID], pipe);
        workerID++;

        parent = open(pipe, O_WRONLY);
        int ret;
        if ((ret = write(parent, orderA, sizeof(Order))) == sizeof(Order))
        {
            printf("[Parent]: sending %d. order to child %d!\n", orderA->id, (int)worker);
            dump_order("Parent sends", orderA);
        }
        else
            err_syserr("failed to write %zu bytes to child %d\n", sizeof(Order), (int)worker);
        close(parent);
    }
}

static void read_response(int worker)
{
    err_remark("Starting to read response from worker %d\n", worker);
    int fd = open(pipes[worker], O_RDONLY);
    if (fd < 0)
        err_syserr("failed to open FIFO '%s' for reading\n", pipes[worker]);
    err_remark("successfully opened FIFO '%s' for reading\n", pipes[worker]);
    int nbytes;
    char buffer[1024];
    while ((nbytes = read(fd, buffer, sizeof(buffer))) > 0)
        err_remark("MSG %i (%d): %.*s\n", worker, shutDown[worker], nbytes, buffer);
    fflush(stdout);
    close(fd);
    err_remark("Finished reading response from worker %d\n", worker);
}

/* There's probably a better way to do this! */
static void get_response(void)
{
    for (int i = 0; i < workerNum; i++)
    {
        for (int j = 0; j < sig_cur; j++)
        {
            if (shutDown[i] == sig_list[j].sig_sender)
            {
                read_response(i);
                sig_list[j].sig_sender = 0;     /* Don't try again */
            }
        }
    }
}

void startJob(void)
{
    pid_t parentPID = getppid();
    sleep(1);
    printf("[Child %d]: is done, sending signal.\n", getpid());
    if (kill(parentPID, SIGUSR2) != 0)
        err_syserr("failed to signal parent process %d\n", (int)parentPID);
    else
        err_remark("signalled parent process %d with SIGUSR2\n", (int)parentPID);
}

void sendPriorityJobs(node priorityHead)
{
    node current = priorityHead;
    while (current != NULL)
    {
        createWorker(current, workerNum);
        workerNum++;
        current = current->next;
    }
    err_remark("All priority jobs sent\n");
}

node createNode(void)
{
    node tmp;
    tmp = (node)malloc(sizeof(struct Order));
    tmp->next = NULL;
    return tmp;
}

node createOrder(char *fullName, char *email, char *phone, char *created, int performance)
{
    node newOrder;
    newOrder = createNode();

    strcpy(newOrder->fullName, fullName);
    strcpy(newOrder->email, email);
    strcpy(newOrder->phone, phone);
    strcpy(newOrder->created, created);
    newOrder->performance = performance;
    newOrder->status = 'N';
    newOrder->id = orderNum + 1;
    orderNum++;

    return newOrder;
}

void sig_handler(int signo, siginfo_t *info, void *context)
{
    sig_list[sig_cur].sig_number = signo;
    clock_gettime(CLOCK_REALTIME, &sig_list[sig_cur].sig_tstamp);
    sig_list[sig_cur].sig_sender = info->si_pid;
    sig_list[sig_cur].sig_contxt = context;
    static const char sig_message[] = "return from signal handler\n";
    write(STDERR_FILENO, sig_message, sizeof(sig_message) - 1);
    sig_cur++;
}

static void print_siginfo(struct SigCaught *info)
{
    struct tm *lt = localtime(&info->sig_tstamp.tv_sec);
    char buffer[32];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
    err_remark("%s.%.3ld: signal %d received from PID %d\n", buffer,
               info->sig_tstamp.tv_nsec / 1000000, info->sig_number,
               info->sig_sender);
}

static void sig_printer(void)
{
    while (sig_prt < sig_cur)
        print_siginfo(&sig_list[sig_prt++]);
}

Пробный прогон

Parent pid: 89404
signal41: 2018-12-30 16:02:57.458 - pid=89404: FIFO /tmp/child.0 created
signal41: 2018-12-30 16:02:57.459 - pid=89405: worker at play!
[Child 89405]: started work on 1. order.
[Parent]: sending 1. order to child 89405!
signal41: 2018-12-30 16:02:57.459 - pid=89404: Parent sends (0x7fc14a800000):
signal41: 2018-12-30 16:02:57.459 - pid=89404: Order: 1, Jane Doe, test1@gmail.com, 12345678, 2018-12-25 8:00, 1000
signal41: 2018-12-30 16:02:57.460 - pid=89404: FIFO /tmp/child.1 created
signal41: 2018-12-30 16:02:57.459 - pid=89405: Read by child: (0x7fc14b001800):
signal41: 2018-12-30 16:02:57.460 - pid=89405: Order: 1, Jane Doe, test1@gmail.com, 12345678, 2018-12-25 8:00, 1000
signal41: 2018-12-30 16:02:57.460 - pid=89406: worker at play!
[Child 89406]: started work on 2. order.
[Parent]: sending 2. order to child 89406!
signal41: 2018-12-30 16:02:57.461 - pid=89404: Parent sends (0x7fc14a801000):
signal41: 2018-12-30 16:02:57.461 - pid=89404: Order: 2, John Doe, test2@gmail.com, 87654321, 2018-12-25 9:00, 1001
signal41: 2018-12-30 16:02:57.461 - pid=89404: All priority jobs sent
signal41: 2018-12-30 16:02:57.461 - pid=89404: suspending...
signal41: 2018-12-30 16:02:57.461 - pid=89406: Read by child: (0x7fc14b80a200):
signal41: 2018-12-30 16:02:57.461 - pid=89406: Order: 2, John Doe, test2@gmail.com, 87654321, 2018-12-25 9:00, 1001
[Child 89405]: is done, sending signal.
return from signal handler
signal41: 2018-12-30 16:02:58.461 - pid=89404: awake again.
signal41: 2018-12-30 16:02:58.461 - pid=89404: suspending...
signal41: 2018-12-30 16:02:58.461 - pid=89405: signalled parent process 89404 with SIGUSR2
[Child 89406]: is done, sending signal.
return from signal handler
signal41: 2018-12-30 16:02:58.462 - pid=89404: awake again.
signal41: 2018-12-30 16:02:58.462 - pid=89404: 2018-12-30 16:02:58.461: signal 31 received from PID 89405
signal41: 2018-12-30 16:02:58.462 - pid=89404: 2018-12-30 16:02:58.462: signal 31 received from PID 89406
signal41: 2018-12-30 16:02:58.462 - pid=89404: Starting to read response from worker 0
signal41: 2018-12-30 16:02:58.462 - pid=89404: successfully opened FIFO '/tmp/child.0' for reading
signal41: 2018-12-30 16:02:58.462 - pid=89406: signalled parent process 89404 with SIGUSR2
signal41: 2018-12-30 16:02:58.462 - pid=89405: successfully reopened FIFO '/tmp/child.0' for writing
signal41: 2018-12-30 16:02:58.463 - pid=89404: MSG 0 (89405): [Child 89405]: ended his daily task.
signal41: 2018-12-30 16:02:58.463 - pid=89405: Message sent to parent: [Child 89405]: ended his daily task.
signal41: 2018-12-30 16:02:58.463 - pid=89404: Finished reading response from worker 0
signal41: 2018-12-30 16:02:58.463 - pid=89404: Starting to read response from worker 1
signal41: 2018-12-30 16:02:58.463 - pid=89404: successfully opened FIFO '/tmp/child.1' for reading
signal41: 2018-12-30 16:02:58.463 - pid=89406: successfully reopened FIFO '/tmp/child.1' for writing
signal41: 2018-12-30 16:02:58.463 - pid=89404: MSG 1 (89406): [Child 89406]: ended his daily task.
signal41: 2018-12-30 16:02:58.464 - pid=89404: Finished reading response from worker 1
signal41: 2018-12-30 16:02:58.464 - pid=89404: child 89405 (corpse 89405) exited with status 0x0000
signal41: 2018-12-30 16:02:58.463 - pid=89406: Message sent to parent: [Child 89406]: ended his daily task.
signal41: 2018-12-30 16:02:58.464 - pid=89404: child 89406 (corpse 89406) exited with status 0x0000
signal41: 2018-12-30 16:02:58.464 - pid=89404: All done!
...