sigsuspend导致第二个子进程无法接收C中的管道消息

huangapple go评论61阅读模式
英文:

Sigsuspend causing second child not be able to receive piped message in C

问题

I've translated the code for you. Here's the translated version:

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

#define CHLD_1_NOTIFY_PARENT SIGUSR1
#define CHLD_2_NOTIFY_PARENT SIGUSR2
#define PARENT_NOTIFY_CHLD_1 SIGUSR1
#define PARENT_NOTIFY_CHLD_2 SIGUSR2

void parent_handler(int signo, siginfo_t* info, void* context) 
{
    int int_msg = info->si_value.sival_int;
    int chld = 2;
    if( int_msg % 2 == 0 )
    {   
        chld = 1;
    }
    
    printf("parent receives %i from child %i with data %i\n", signo, chld, int_msg );
}

int main()
{
    pid_t parent_pid, pid, pid_2;
    sigset_t oldmask_1, oldmask_2, newmask_1, newmask_2;
    union sigval value;
    struct sigaction action;
    int fds[2];
    pipe(fds);

    int fds_2[2];
    pipe(fds_2);

    parent_pid = getpid();
    
    sigemptyset(&newmask_1); 
    sigaddset(&newmask_1, CHLD_1_NOTIFY_PARENT);
    sigprocmask(SIG_BLOCK, &newmask_1, &oldmask_1); 
    
    sigemptyset(&newmask_2); 
    sigaddset(&newmask_2, CHLD_2_NOTIFY_PARENT);
    sigprocmask(SIG_BLOCK, &newmask_2, &oldmask_2); 
    

    action.sa_flags = SA_SIGINFO; 
    action.sa_sigaction = parent_handler;

    if (sigaction(CHLD_1_NOTIFY_PARENT, &action, NULL) == -1) { 
        perror("sigusr: sigaction");
    }

    if (sigaction(CHLD_2_NOTIFY_PARENT, &action, NULL) == -1) { 
        perror("sigusr: sigaction");
    }

    if ( (pid = fork() ) ) 
    {    /* parent */

        if( ( pid_2 = fork() )== 0 ) // 2nd child
        {   
            printf("2nd child started\n");
            
            value.sival_int = 43;

            sigqueue( parent_pid, CHLD_2_NOTIFY_PARENT, value );

            printf("2nd child sends CHLD_2_NOTIFY_PARENT\n");
            
            close(fds[0]);
            close(fds[1]);
            close(fds_2[1]);
            char buffer[6];
            read(fds_2[0], buffer, sizeof(buffer));
            printf("2nd child receives through pipe: %s.\n", buffer);
            close(fds_2[0]);
            
            printf("2nd child terminates\n");

        }
        else
        {
            sleep(1); 

            sigsuspend(&oldmask_1);
            
            close(fds[0]);
            write(fds[1], "hello", 6);
            wait(NULL);
            
            sigsuspend(&oldmask_2);
            close(fds[1]);
            close(fds_2[0]);
            write(fds_2[1], "hello", 6);
            wait(NULL);
            close(fds_2[1]);

            waitpid(pid,  NULL, 0 );
            waitpid( pid_2, NULL, 0 );
            printf("Parent terminates\n");
        }
        
    }
    else /* 1st child */
    {                 
        printf("1st child starts\n");

        value.sival_int = 42;
        
        sigqueue( parent_pid, CHLD_1_NOTIFY_PARENT, value );

        printf("1st child sends CHLD_1_NOTIFY_PARENT signal to parent\n");

        close(fds[1]);
        char buffer[6];
        read(fds[0], buffer, sizeof(buffer));
        printf("1st child receives through pipe: %s.\n", buffer);
        close(fds[0]);
        
        printf("1st child terminates\n");
    }
}

I've corrected some formatting and language issues in your code to make it more readable. Let me know if you need further assistance!

英文:

I'm workng on a C program with which I'd like to implement a scenario when a parent and two children processes are communicating with each other via two separate unnamed pipes reserved for each of the children. Before this both children should send a signal to the parent. That's not a problem. However, in case the parent would like to write the second unnamed pipe fds_2 in order for the second child to access its message, then I'm unable to achieve the deisred goal.

I attempted to accomplish the desired outcome with the help of the SIGUSR1 and SIGUSR2 constants. They're reserved for the first and second child, respectively. First, the parent has to receive all the signals. and only then it shall send the message to both children on separate pipes. In the parent I attempt to open the pipes for writing only. In the children following the sigqueue call I attempt to open the pipes for reading only.

I experience that only the first child receives the text message and then the execution hangs.

I know that printf() inside a handler function body is not desired, but I'm only including that for experimenting purposes.

#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;signal.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;string.h&gt;
#include &lt;time.h&gt;
#include &lt;sys/stat.h&gt;
#define CHLD_1_NOTIFY_PARENT SIGUSR1
#define CHLD_2_NOTIFY_PARENT SIGUSR2
#define PARENT_NOTIFY_CHLD_1 SIGUSR1
#define PARENT_NOTIFY_CHLD_2 SIGUSR2
int main()
{
pid_t parent_pid, pid, pid_2;
sigset_t newmask, oldmask;
union sigval value;
struct sigaction action;
int fds[2];
pipe(fds);
int fds_2[2];
pipe(fds_2);
parent_pid = getpid();
if ( (pid = fork() ) ) 
{    /*parent*/
void parent_handler( int signo, siginfo_t* info, void* context );
sigemptyset(&amp;newmask); 
sigaddset(&amp;newmask, CHLD_1_NOTIFY_PARENT); 
sigaddset(&amp;newmask, CHLD_2_NOTIFY_PARENT); 
sigprocmask(SIG_BLOCK, &amp;newmask, &amp;oldmask); 
action.sa_flags = SA_SIGINFO; 
action.sa_sigaction = parent_handler;
if (sigaction(CHLD_1_NOTIFY_PARENT, &amp;action, NULL) == -1) { 
perror(&quot;sigusr: sigaction&quot;);
}
if (sigaction(CHLD_2_NOTIFY_PARENT, &amp;action, NULL) == -1) { 
perror(&quot;sigusr: sigaction&quot;);
}
if( ( pid_2 = fork() )== 0 ) //2. child
{   
printf(&quot;2. child started\n&quot;);
value.sival_int = 43;
sigqueue( parent_pid, CHLD_2_NOTIFY_PARENT, value );
printf(&quot;2. child sends CHLD_2_NOTIFY_PARENT\n&quot;);
close(fds[0]);
close(fds[1]);
close(fds_2[1]);
char buffer[6];
read(fds_2[0], buffer, sizeof(buffer));
printf(&quot;2. child receives through pipe: %s.\n&quot;, buffer);
close(fds_2[0]);
printf(&quot;2. child terminates\n&quot;);
}
else
{
//value.sival_int = 44;
//sigqueue( pid, PARENT_NOTIFY_CHLD_1, value );
sleep(1); 
sigsuspend(&amp;oldmask);
close(fds[0]);
write(fds[1], &quot;hello&quot;, 6);
wait(NULL);
sigsuspend(&amp;oldmask);
close(fds[1]);
close(fds_2[0]);
write(fds_2[1], &quot;hello&quot;, 6);
wait(NULL);
close(fds_2[1]);
waitpid(pid,  NULL, 0 );
waitpid( pid_2, NULL, 0 );
printf(&quot;Parent terminates\n&quot;);
}
}
else /* 1. child */
{                 
printf(&quot;1. child starts\n&quot;);
//void chld_handler( int signo, siginfo_t* info, void* context );
sigemptyset(&amp;newmask); 
sigaddset(&amp;newmask, PARENT_NOTIFY_CHLD_1); 
sigprocmask(SIG_BLOCK, &amp;newmask, &amp;oldmask);
action.sa_flags = SA_SIGINFO; 
//action.sa_sigaction = chld_handler;
if (sigaction( PARENT_NOTIFY_CHLD_1, &amp;action, NULL) == -1) { 
perror(&quot;sigusr: sigaction&quot;);
}
value.sival_int = 42;
sigqueue( parent_pid, CHLD_1_NOTIFY_PARENT, value );
printf(&quot;1. child sends CHLD_1_NOTIFY_PARENT signal to parent\n&quot;);
close(fds[1]);
char buffer[6];
read(fds[0], buffer, sizeof(buffer));
printf(&quot;1. child receives through pipe: %s.\n&quot;, buffer);
close(fds[0]);
printf(&quot;1. child terminates\n&quot;);
}
}
void parent_handler(int signo, siginfo_t* info, void* context) 
{
int int_msg = info-&gt;si_value.sival_int;
int chld = 2;
if( int_msg % 2 == 0 )
{   
chld = 1;
}
printf(&quot;parent receives %i from child %i. with data %i\n&quot;, signo, chld, int_msg );
}

Thank you very much in advance!

EDIT:
The modified version in code:

#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;signal.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;string.h&gt;
#include &lt;time.h&gt;
#include &lt;sys/stat.h&gt;
#define CHLD_1_NOTIFY_PARENT SIGUSR1
#define CHLD_2_NOTIFY_PARENT SIGUSR2
#define PARENT_NOTIFY_CHLD_1 SIGUSR1
#define PARENT_NOTIFY_CHLD_2 SIGUSR2
void parent_handler(int signo, siginfo_t* info, void* context) 
{
int int_msg = info-&gt;si_value.sival_int;
int chld = 2;
if( int_msg % 2 == 0 )
{   
chld = 1;
}
printf(&quot;parent receives %i from child %i. with data %i\n&quot;, signo, chld, int_msg );
}
int main()
{
pid_t parent_pid, pid, pid_2;
sigset_t oldmask_1, oldmask_2, newmask_1, newmask_2;
union sigval value;
struct sigaction action;
int fds[2];
pipe(fds);
int fds_2[2];
pipe(fds_2);
parent_pid = getpid();
sigemptyset(&amp;newmask_1); 
sigaddset(&amp;newmask_1, CHLD_1_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &amp;newmask_1, &amp;oldmask_1); 
sigemptyset(&amp;newmask_2); 
sigaddset(&amp;newmask_2, CHLD_2_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &amp;newmask_2, &amp;oldmask_2); 
action.sa_flags = SA_SIGINFO; 
action.sa_sigaction = parent_handler;
if (sigaction(CHLD_1_NOTIFY_PARENT, &amp;action, NULL) == -1) { 
perror(&quot;sigusr: sigaction&quot;);
}
if (sigaction(CHLD_2_NOTIFY_PARENT, &amp;action, NULL) == -1) { 
perror(&quot;sigusr: sigaction&quot;);
}
if ( (pid = fork() ) ) 
{    /*parent*/
if( ( pid_2 = fork() )== 0 ) //2. child
{   
printf(&quot;2. child started\n&quot;);
value.sival_int = 43;
sigqueue( parent_pid, CHLD_2_NOTIFY_PARENT, value );
printf(&quot;2. child sends CHLD_2_NOTIFY_PARENT\n&quot;);
close(fds[0]);
close(fds[1]);
close(fds_2[1]);
char buffer[6];
read(fds_2[0], buffer, sizeof(buffer));
printf(&quot;2. child receives through pipe: %s.\n&quot;, buffer);
close(fds_2[0]);
printf(&quot;2. child terminates\n&quot;);
}
else
{
//value.sival_int = 44;
//sigqueue( pid, PARENT_NOTIFY_CHLD_1, value );
sleep(1); 
sigsuspend(&amp;oldmask_1);
close(fds[0]);
write(fds[1], &quot;hello&quot;, 6);
wait(NULL);
sigsuspend(&amp;oldmask_2);
close(fds[1]);
close(fds_2[0]);
write(fds_2[1], &quot;hello&quot;, 6);
wait(NULL);
close(fds_2[1]);
waitpid(pid,  NULL, 0 );
waitpid( pid_2, NULL, 0 );
printf(&quot;Parent terminates\n&quot;);
}
}
else /* 1. child */
{                 
printf(&quot;1. child starts\n&quot;);
value.sival_int = 42;
sigqueue( parent_pid, CHLD_1_NOTIFY_PARENT, value );
printf(&quot;1. child sends CHLD_1_NOTIFY_PARENT signal to parent\n&quot;);
close(fds[1]);
char buffer[6];
read(fds[0], buffer, sizeof(buffer));
printf(&quot;1. child receives through pipe: %s.\n&quot;, buffer);
close(fds[0]);
printf(&quot;1. child terminates\n&quot;);
}
}

The modified version regarding a terminating output:

1. child starts
1. child sends CHLD_1_NOTIFY_PARENT signal to parent
2. child started
2. child sends CHLD_2_NOTIFY_PARENT
parent receives 10 from child 1. with data 42
1. child receives through pipe: hello.
1. child terminates
parent receives 12 from child 2. with data 43
2. child receives through pipe: hello.
2. child terminates
Parent terminates

The new version sometimes doesn't block, sometimes blocks.

答案1

得分: 1

以下是您要翻译的内容:

如果您希望第一个sigsuspend允许传递CHLD_1_NOTIFY_PARENT并使CHLD_2_NOTIFY_PARENT保持阻塞状态,您需要使用一个阻塞CHLD_2_NOTIFY_PARENT的掩码来调用它。您当前的代码是:

sigemptyset(&newmask_1); 
sigaddset(&newmask_1, CHLD_1_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &newmask_1, &oldmask_1); 

sigemptyset(&newmask_2); 
sigaddset(&newmask_2, CHLD_2_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &newmask_2, &oldmask_2); 
...
sigsuspend(&oldmask_1);

但这将允许传递CHLD_1_NOTIFY_PARENTCHLD_2_NOTIFY_PARENT。以下是我运行它时的输出:

2. 子进程已启动
2. 子进程发送CHLD_2_NOTIFY_PARENT信号
1. 子进程启动
1. 子进程发送CHLD_1_NOTIFY_PARENT信号给父进程
父进程从子进程2接收到12,数据为43
父进程从子进程1接收到10,数据为42
1. 子进程通过管道接收到:hello。
1. 子进程终止
^C

第一个sigsuspend应该更改为使用一个掩码,该掩码是进程的原始掩码与CHLD_2_NOTIFY_PARENT的并集。

您的第二个sigsuspend如下:

sigsuspend(&oldmask_2);

是正确的,因为您希望允许传递CHLD_2_NOTIFY_PARENT,而oldmask_2是进程的原始掩码,其中包含CHLD_1_NOTIFY_PARENT
(此时,子进程1已退出并已等待,因此甚至可以在此处使用原始信号掩码。)

以下是我所做的更改:

sigset_t origmask, mask_1, mask_2;

sigprocmask(SIG_BLOCK, NULL, &origmask); 
mask_1 = origmask;
sigaddset(&mask_1, CHLD_1_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &mask_1, NULL);

mask_2 = origmask;
sigaddset(&mask_2, CHLD_2_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &mask_2, NULL);

输出如下:

2. 子进程已启动
2. 子进程发送CHLD_2_NOTIFY_PARENT信号
1. 子进程启动
1. 子进程发送CHLD_1_NOTIFY_PARENT信号给父进程
父进程从子进程1接收到10,数据为42
1. 子进程通过管道接收到:hello
1. 子进程终止
父进程从子进程2接收到12,数据为43
2. 子进程通过管道接收到:hello
2. 子进程终止
父进程终止
英文:

If you want the first sigsuspend to allow CHLD_1_NOTIFY_PARENT to be delivered and CHLD_2_NOTIFY_PARENT to remain blocked, you need to call it with a mask that blocks CHLD_2_NOTIFY_PARENT. Your current code is:

sigemptyset(&amp;newmask_1); 
sigaddset(&amp;newmask_1, CHLD_1_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &amp;newmask_1, &amp;oldmask_1); 
sigemptyset(&amp;newmask_2); 
sigaddset(&amp;newmask_2, CHLD_2_NOTIFY_PARENT);
sigprocmask(SIG_BLOCK, &amp;newmask_2, &amp;oldmask_2); 
...
sigsuspend(&amp;oldmask_1);

but this will allow delivery of both CHLD_1_NOTIFY_PARENT and CHLD_2_NOTIFY_PARENT. Here is the output when I ran it:

2. child started
2. child sends CHLD_2_NOTIFY_PARENT
1. child starts
1. child sends CHLD_1_NOTIFY_PARENT signal to parent
parent receives 12 from child 2. with data 43
parent receives 10 from child 1. with data 42
1. child receives through pipe: hello.
1. child terminates
^C

The first sigsuspend should be changed to use a mask that is the union of the process's original mask and CHLD_2_NOTIFY_PARENT.

Your second sigsuspend,

sigsuspend(&amp;oldmask_2);

is OK, because you want to allow CHLD_2_NOTIFY_PARENT to be delivered, and oldmask_2 is the process's original mask with CHLD_1_NOTIFY_PARENT added.
(At this point, child 1 has exited and has been waited for, so even the orignial signal mask could be used here.)

Here are the changes I made:

34c34
&lt;     sigset_t oldmask_1, oldmask_2, newmask_1, newmask_2;
---
&gt;     sigset_t origmask, mask_1, mask_2;
45,47c45,48
&lt;     sigemptyset(&amp;newmask_1); 
&lt;     sigaddset(&amp;newmask_1, CHLD_1_NOTIFY_PARENT);
&lt;     sigprocmask(SIG_BLOCK, &amp;newmask_1, &amp;oldmask_1); 
---
&gt;     sigprocmask(SIG_BLOCK, NULL, &amp;origmask); 
&gt;     mask_1 = origmask;
&gt;     sigaddset(&amp;mask_1, CHLD_1_NOTIFY_PARENT);
&gt;     sigprocmask(SIG_BLOCK, &amp;mask_1, NULL); 
49,51c50,52
&lt;     sigemptyset(&amp;newmask_2); 
&lt;     sigaddset(&amp;newmask_2, CHLD_2_NOTIFY_PARENT);
&lt;     sigprocmask(SIG_BLOCK, &amp;newmask_2, &amp;oldmask_2); 
---
&gt;     mask_2 = origmask;
&gt;     sigaddset(&amp;mask_2, CHLD_2_NOTIFY_PARENT);
&gt;     sigprocmask(SIG_BLOCK, &amp;mask_2, NULL); 
99c100
&lt;             sigsuspend(&amp;oldmask_1);
---
&gt;             sigsuspend(&amp;mask_2);
106c107
&lt;             sigsuspend(&amp;oldmask_2);
---
&gt;             sigsuspend(&amp;mask_1);

The output is this:

2. child started
2. child sends CHLD_2_NOTIFY_PARENT
1. child starts
1. child sends CHLD_1_NOTIFY_PARENT signal to parent
parent receives 10 from child 1. with data 42
1. child receives through pipe: hello.
1. child terminates
parent receives 12 from child 2. with data 43
2. child receives through pipe: hello.
2. child terminates
Parent terminates

huangapple
  • 本文由 发表于 2023年5月14日 20:23:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76247467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定