fork()이후 자식 프로세스끼리의 시그널 보내기

tstudy119의 이미지

fork()함수를 이용해서 자식 프로세스를 3개 만든 후,

자식 프로세스끼리 환형으로 시그널을 주는 게 가능한가요?

A -> B -> C -> A 이런 식으로요.......

문제는 pipe나 메시지 큐같은 ipc를 사용하지 말고 시그널 만으로 구현해야 하는데,

부모랑 자식끼리 시그널 보내기는 부모 프로세스에서 fork()의 리턴 값으로, 자식 프로세스 에서는 getppid()함수로 pid를 얻으면간단한데,

같은 부모프로세스 밑의 다른 자식프로세스는 ipc를 사용하지 않고서는 서로 pid를 알 수 있는 방법이 없나요?ㅜㅜ

chanik의 이미지

부모 프로세스까지 포함한다면 특별한 코딩 없이도 환형구조를 간단히 만들 수 있습니다.

child[] 배열에는 순차적으로 자식 프로세스 pid가 들어가게 되는데, 이 배열 내용물도 fork()시 복제되므로 각 자식프로세스는 자기보다 먼저 만들어진 형제 프로세스의 pid는 알 수 있습니다. 따라서 자신의 직전에 만들어진 형제프로세스를 시그널 송신대상으로 삼으면 됩니다. 다만, 첫번째 자식은 다른 형제의 pid를 알 수 없으므로 부모 프로세스를 송신대상으로 삼고, 부보 프로세스는 마지막 자식프로세스를 송신대상으로 삼게하면 환형구조가 완성되는 것이죠.

부모 -> 세번째자식 -> 두번째자식 -> 첫번째자식 -> (부모) 의 순환고리가 됩니다.

#include <stdio.h>
#include <signal.h>
 
#define NUM_CHILD 3
 
void sig_usr1(int signo)
{
  printf("%d: I Received SIGUSR1(%d)\n\n", getpid(), SIGUSR1);
}
 
int main()
{
    int i;
    pid_t child[NUM_CHILD];
 
    signal(SIGUSR1, (void *)sig_usr1);
 
    for(i=0; i<NUM_CHILD; i++) {
        child[i] = fork();
        if(child[i] == 0)               /* break if child process */
            break;
    }
 
    pid_t pid_prev;
    if(i == 0)  pid_prev = getppid();   /* first child -> parent        */
    else        pid_prev = child[i-1];  /* 2nd ~ nth   -> (n-1)th child */
                                        /* parent      -> last child    */
    /* make timing difference for each process */
    while(i-- > 0)
        sleep(1);
 
    printf("%d: I'm sending SIGUSR1(%d) to process %d\n", getpid(), SIGUSR1, pid_prev);
    kill(pid_prev, SIGUSR1);
 
    for(i=0; i<10; i++)
        sleep(1);
 
    return 0;
}

실행결과는 아래와 같습니다.

$ gcc -o sample sample.c
$ ./sample &
[1] 24815
24816: I'm sending SIGUSR1(10) to process 24815
24815: I Received SIGUSR1(10)
 
24817: I'm sending SIGUSR1(10) to process 24816
24816: I Received SIGUSR1(10)
 
24818: I'm sending SIGUSR1(10) to process 24817
24817: I Received SIGUSR1(10)
 
24815: I'm sending SIGUSR1(10) to process 24818
24818: I Received SIGUSR1(10)
$ pstree -p 24815
sample(24815)─┬─sample(24816)
               ├─sample(24817)
               └─sample(24818)
tstudy119의 이미지

모든 자식 프로세스의 PID를 다 아는 부모 프로세스를 끼우면 가능한 거였네요ㅜㅜ

정말 감사합니다.

chanik의 이미지

부모 프로세스까지 환형구조에 참가시키고 싶지 않다면,

각 프로세스가 다른 자식 프로세스의 pid를 알아낼 일반적인 방법이 필요한데, 부모프로세스 pid를 주고 그 자식프로세스를 찾아주는 'pgrep -P $ppid' 명령을 이용할 수 있을 것입니다. 물론 프로세스 정보에 접근하는 다른 방법도 있겠죠..

샘플코드와 실행결과를 올립니다. 깔끔하지는 않지만 참고는 될 것입니다.

#include <stdio.h>
#include <signal.h>
 
#define NUM_CHILD 3
 
void sig_usr1(int signo)
{
  printf("%d: I Received SIGUSR1(%d)\n\n", getpid(), SIGUSR1);
}
 
pid_t find_next_sibling()
{
    pid_t child[NUM_CHILD];
    char buf[16];
    char cmd[32];
 
    sprintf(cmd, "pgrep -P %d", getppid());
    FILE *fp = popen(cmd, "r");
    if(NULL == fp) {
        perror("popen() failed");
        return -1;
    }
 
    pid_t mine = getpid();
    int j=0, me=-1;
    while(fgets(buf, 16, fp)) {
        pid_t pid = (pid_t)atoi(buf);
        child[j++] = pid;
        if(pid == mine)
            me = pid;
    }
    pclose(fp);
 
    if(me != -1)
        return child[(me+1)%NUM_CHILD];
    else
        return 0;
}
 
int main()
{
    int i;
 
    signal(SIGUSR1, (void *)sig_usr1);
 
    for(i=0; i<NUM_CHILD; i++) {
        if(fork() ==  0)                /* break if child process */
            break;
    }
 
    pid_t pid_next;
    if(i < NUM_CHILD) {
        sleep(1);                       /* wait until every child process be created */
        pid_next = find_next_sibling();
 
        while(i-- > 0)                  /* make timing difference for each process */
            sleep(1);
 
        if(pid_next) {
            printf("%d: I'm sending SIGUSR1(%d) to process %d\n", getpid(), SIGUSR1, pid_next);
            kill(pid_next, SIGUSR1);
        }
    }
 
    for(i=0; i<10; i++)
        sleep(1);
 
    return 0;
}

$ ./sample2 &
[1] 24920
24921: I'm sending SIGUSR1(10) to process 24922
24922: I Received SIGUSR1(10)
 
24922: I'm sending SIGUSR1(10) to process 24923
24923: I Received SIGUSR1(10)
 
24923: I'm sending SIGUSR1(10) to process 24921
24921: I Received SIGUSR1(10)
$ pstree -p 24920
sample2(24920)─┬─sample2(24921)
                ├─sample2(24922)
                └─sample2(24923)
tstudy119의 이미지

어떻게 풀어야 할지난감했는데,,, 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.