簡體   English   中英

C,Fork和exec進程,並發送信號

[英]C, Fork and exec process, and sending signals

基本上我有兩個代碼。 其中之一必須在外殼“ TIME!”中打印。 每次收到SIGUSR1信號時。 我們稱它為exercici.c

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

char buffer[1000];

void captura_signal(int signum){

    if(signum == SIGUSR1){
        sprintf(buffer,"TIME! %d\n",getpid());
        write(1,buffer,strlen(buffer));
    }
}


int main(int argc, char *argv[]){
    signal(SIGUSR1, captura_signal);
    while(1){
        pause();
    }

}

另一個,必須創建三個子進程(僅一個父進程和三個子進程),並在每個子進程上創建execlp exercici.c。 然后,父母必須每秒向一個孩子發送一個SIGUSR1,每秒遞增一次。 我稱它為exercici2.c

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


bool ready = 1;

void  sigAlarm(int sig){
    if (sig == SIGALRM){
        ready = 1;
    }
}


int main(int argc, char *argv[]){
    int pid[3];
    signal(SIGALRM,sigAlarm);
    for(int i = 0; i<3;i++){
        if((pid[i]=fork()) == 0){
            execlp("./exercici","exercici",(char*)NULL);
        }
    }
    int j =0;
    while(1){
        if(ready){
            ready = 0;
            kill(pid[j],SIGUSR1);
            j = ((j+1)%3);
            alarm(1);
        }
    }
}

問題是,當我執行exercici2.c時,它僅創建2個進程,而我僅收到TIME! 其中2個。 跳過pid [0]。

外殼圖片

了解fork()和子進程的創建以及子進程將執行代碼的哪一部分有點棘手。 在這里,您從每個子進程中調用while(1)循環,這部分代碼不是在主進程中執行,而是僅在子進程內部執行。 因此,“ j”始終為0,實際上您正在執行kill(pid [0],SIGUSR1); ( 3次)。

最好從父進程控制子進程。 請參閱下面的修改后的代碼,它會為您工作。

int parentPID = 0;

int main(int argc, char *argv[]){
 int pid[3];
 parentPID = getpid();
 signal(SIGALRM,sigAlarm);
 for(int i = 0; i<3;i++){
    if((pid[i]=fork()) == 0){
        printf("child :%d\n",i);
        execlp("./exercici","exercici",(char*)NULL);
    }
 }
 if (parentPID == getpid()){
     sleep(5);/* Let the 3 childs create */
     int j = 0;
     int ready = 1;
     while(ready){
       kill(pid[j],SIGUSR1);
       j = ((j+1)%3);
       ready = j;
       alarm(1);
     }
    }

}

發生此問題的原因是-

int j =0;
while(1){
    if(ready){
        ready = 0;
        kill(pid[j],SIGUSR1);
        j = ((j+1)%3);
        alarm(1);
    }
}

在父進程中。

在這里,您使用0初始化j ,然后在while循環中kill()在第一次迭代中將SIGUSR1發送到pid [0]。

每個信號都有一個“默認配置”-進程在收到該信號時默認執行的操作。

signal(7)手冊頁-

SIGUSR1和SIGUSR2的默認配置是- 期限 ,這意味着終止進程。

信號值操作注釋

──────────────────────────────────

SIGUSR1 30、10、16術語用戶定義信號1

SIGUSR2 31、12、17術語用戶定義信號2

在您的exercici子程序中,您正在更改信號SIGUSR1的處置,並將處置設置為處理函數captura_signal

 signal(SIGUSR1, captura_signal)

在您的情況下,發生的事情是分支時具有pid [0]的子進程,並且在子進程執行exercici並設置SIGUSR1信號處理程序之前,父進程將SIGUSR1發送到pid [0]。 並且由於SIGUSR1的默認配置是終止進程,因此pid [0]子進程將終止並標記為已失效。

在我的系統上,我可以在ps命令的輸出中看到-

ps -eaf | grep exercici

根29210 19542 86 20:51 pts 5 00:00:04 ./exercici2 -------->父進程

根29211 29210 0 20:51點數5 00:00:00 [exercici2] <已失效> ------>子進程在執行exercici之前收到信號SIGUSR1

根29212 29210 0 20:51 pts 5 00:00:00 exercici -------->子進程成功執行了exercici並更改了SIGUSR1的默認配置

根29213 29210 0 20:51 pts 5 00:00:00 exercici -------->子進程成功執行了exercici並更改了SIGUSR1的默認配置

在這里您可以看到帶有pid 29211的第一個子進程被標記為defunct

您可以通過多種方式解決此問題。 其中之一是通過添加此語句來簡單地忽略父進程中的SIGUSR1-

signal(SIGUSR1,SIG_IGN);

在父進程開始時分叉子進程的某個位置。

子進程從父進程繼承信號處理程序。 因此,如果子進程收到SIGUSR1,則在使用新進程(exercici)執行當前進程映像之前,它將忽略它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM