简体   繁体   English

从子进程发送信号并以这种方式在父进程中接收是否正确?

[英]Is it correct to send signals from child processes and receive in this way in parent?

My task is to have multiple childs and a parents which are communicating between each other. 我的任务是让多个孩子和一个父母之间相互交流。 I read the tasks from a file, and create childs depends on the number of the tasks. 我从文件中读取任务,然后根据任务数创建子项。 In the parent I send tasks to different children. 在父母中,我将任务发送给其他孩子。 So a child can "work on" a task. 因此,孩子可以“完成”一项任务。 Every child has its pipe. 每个孩子都有自己的烟斗。 After a child got the data and do some work it has to send a signal to his parent, and a bit later send a message through his pipe to say that "I'm finished today". 孩子获得数据并完成一些工作后,必须向父母发送信号,稍后再通过他的管道发送一条消息,说“我今天结束了”。 I'm not sure how to handle receiving multiple signals. 我不确定如何处理接收多个信号。 How should I achieve this? 我应该如何实现?

Code: 码:

#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);
}

I'm not sure how to send multiple signals and end of the day messages, and receive it in the parent. 我不确定如何发送多个信号和一天结束的消息,并在父级中接收它。

To some extent rehashing points made in the commentary to the question, not excluding the chat session , here is an answer in several parts. 在某种程度上,对问题的注释中的重新讨论要点,不排除聊天会话 ,这里是一个由几个部分组成的答案。

Terminology 术语

It is generally best to reserve the term 'pipes' for the type of pipe created by the pipe() system call (or function wrapping a system call), using the term FIFO for 'named pipes' created by the mkfifo() system call. 通常,最好对pipe()系统调用(或包装系统调用的函数pipe()创建的pipe()类型保留术语“管道”,而对mkfifo()系统调用创建的“命名管道”保留术语FIFO。 。 Note that you can't open pipes with the open() system call; 请注意,您无法使用open()系统调用打开管道; you can't open a FIFO except with open() or its minor variant openat() . 您只能使用open()或其较小的变体openat()来打开FIFO。

Also, see Is it a good idea to typedef pointers? 另外,请参见typedef指针是一个好主意吗? to which the short answer is generally "No". 简短的回答通常是“否”。 It caused some confusion in your code, where you have: 它在您的代码中造成了一些混乱:

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

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

In both cases, the variable is a pointer to an Order (a node ), and the extra indirection of the & is wrong because sizeof(Order *) != sizeof(Order) — and you're sending the wrong data down the pipe, and reading to the wrong place. 在这两种情况下,变量都是指向Ordernode )的指针,并且&的额外间接sizeof(Order *) != sizeof(Order)是错误的,因为sizeof(Order *) != sizeof(Order) —您在管道中发送了错误的数据,然后将其阅读到错误的位置。 There would be less chance of confusion if you had typedef struct Order Order; 如果您有typedef struct Order Order;那么混乱的机会会更少typedef struct Order Order; and the variables were of type Order * . 并且变量的类型为Order *

Version 1 版本1

At one point in the discussion I sent the following (flawed) code. 在讨论的某一时刻,我发送了以下(有缺陷的)代码。 Surprisingly, it worked, more or less. 令人惊讶的是,它或多或少地起作用了。 But that was mostly by accident, not least because of of the read/write problems shown. 但这主要是偶然的,尤其是由于显示的读/写问题。

This code uses library function available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory. 该代码使用GitHub上我的SOQ (堆栈溢出问题)存储库中可用的库函数,作为src / libsoq子目录中的stderr.cstderr.h文件。

Defective code — do not use 代码有缺陷-请勿使用

/* 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__);
}

Despite its flaws, and the extent to which it ignores the advice on How to avoid using printf() in a signal handler , it sort of works. 尽管它有缺陷,并且在某种程度上忽略了如何避免在信号处理程序中使用printf()的建议,但是它还是可以工作的。 Fortunately, the child doesn't try to do anything with the data it is supposed to read from the parent. 幸运的是,孩子不会尝试对应该从父母那里读取的数据做任何事情。

Sample run 样品运行

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!

You can see garbage in the dump of the information received from the parent. 您可以在从父级收到的信息转储中看到垃圾。 However, this does show that the SA_RESTART flag is important in the sigaction() call. 但是,这确实表明SA_RESTART标志在sigaction()调用中很重要。 Without that, the waitpid() function returns errors, which this program catches and reports. waitpid()waitpid()函数将返回错误,该程序将捕获并报告错误。

Version 2 版本2

This is mostly working code, which actually uses a sigsuspend() loop roughly like an earlier incarnation of your code did. 这主要是工作代码,实际上使用了sigsuspend()循环,大致就像您的代码的早期版本一样。 However, it is somewhat different. 但是,有些不同。 In particular, this gets information back from the children. 特别是,这将从孩子那里获得信息。 It does so using the same FIFO that was used to relay the information from the parent to the children. 它使用用于将信息从父级中继到子级的相同FIFO来实现。 The parent initially opens the FIFO for writing, then writes a message to the child, then closes the FIFO. 父级首先打开FIFO进行写入,然后向子级写入一条消息,然后关闭FIFO。 Meanwhile, the child opens the FIFO for reading, reads the message, and then closes the FIFO. 同时,孩子打开FIFO进行读取,读取消息,然后关闭FIFO。 When all the children have signalled the parent (using the sigsuspend loop), then it reads the responses, with the children opening the FIFO for writing, writing and closing the FIFO, while the parent opens the FIFO for reading, reads the response, and closes the FIFO again. 当所有孩子都向父sigsuspend发出信号(使用sigsuspend循环)后,它将读取响应,其中孩子打开FIFO进行写入,写入和关闭FIFO,而父sigsuspend打开FIFO进行读取,读取响应,然后再次关闭FIFO。 Only then does the parent go into a loop waiting for its children to die (multi-process work on Unix-like systems is a morbid business, what with dead children and zombies and all the rest). 只有这样,父进程才会进入循环等待其子进程死亡(在类Unix系统上的多进程工作是一种病态的业务,包括死掉的子进程和僵尸以及所有其他事务)。

This code also removes the FIFOs both before and after it is run. 此代码还可以在运行之前和之后删除FIFO。 The FIFO names in the /tmp directory are easy to deduce, and hence it is easy to break the program (create a directory /tmp/child.0 , for example). /tmp目录中的FIFO名称很容易推论,因此很容易破坏程序(例如,创建目录/tmp/child.0 )。 A better solution would use mkstemp() or a similar function to create the FIFO names (noting that mkstemp() actually creates a file, not a FIFO; there isn't a direct mechanism to create a uniquely-named FIFO that I know of). 更好的解决方案是使用mkstemp()或类似的函数来创建FIFO名称(注意mkstemp()实际上是创建文件而不是FIFO;没有直接的机制来创建我知道的唯一命名的FIFO) )。

Usable code, but still unpolished 可用的代码,但仍未打磨

/* 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++]);
}

Sample run 样品运行

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!

Basically, most of the cases @JonathanLeffler's code work but when the system receive two signal at the same time it won't work at all, and you'll be not able to get the second signal. 基本上,大多数情况下,@ JonathanLeffler的代码都可以工作,但是当系统同时接收到两个信号时,它将根本无法工作,并且您将无法获得第二个信号。 What I did, to solve this issue was to use real time signal instead of SIGUSR1|2. 为了解决这个问题,我所做的就是使用实时信号而不是SIGUSR1 | 2。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM