【问题标题】:System Calls in C signals and forkC 信号和 fork 中的系统调用
【发布时间】:2017-05-07 22:23:30
【问题描述】:

您好,我想用 C 语言程序解决这个问题。

"编写一个 C 程序,其中一个进程 F 创建一个子进程 C。 子进程 C 等待用户输入密码,如果正确则向父进程发送信号 SIGUSR1,如果 3 次尝试后密码仍然不正确,则向父进程发送 SIGUSR2 信号并终止;如果它收到来自父亲的 SIGUSR1 信号,则必须停止查看“超时”消息。

他的父亲在 30 秒后(如果它没有收到孩子的任何信号)必须向孩子发送信号 SIGUSR1 并以 exit(1) 结束;如果它接收到 SIGUSR1 信号必须以 exit(0) 结束;如果它收到信号 SIGUSR2 必须以 exit (2) 结束。"

我正在尝试解决它,但我卡住了。这就是我所做的:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>

void fatherprocess(int mysignal){
    if (mysignal == SIGUSR1) {
        printf("ACCESS GRANTED!\n");
        exit(0);
    }

    if (mysignal == SIGUSR2){
        printf("ACCESS DISCARDED! More than 3 tentatives!\n");
        exit(2);
    }

}


void childprocess(int mysignal){
    if (mysignal == SIGUSR1) {
        printf("TIMEOUT\n");
        exit(1);
    }
}


int main(int argc, char *argcv[]){
    int fatherpid, childpid;
    char enteredpassword[], password[] = "test";
    int i =0;
    unsigned int time_to_sleep = 30;

   fatherpid = getpid();
   childpid = fork();

   if (childpid == 0) {
       printf("Child Process waiting for a password\n");
       while (1){
           if (i < 3) {
               printf("Enter Password: ");
               scanf("%s", enteredpassword);
               if (enteredpassword == password)
                   signal(SIGUSR1, fatherprocess);
           } else {
               signal(SIGUSR2, fatherprocess);
               exit(1);
           }
          i++;
      }
    } else {
        printf("Father Process\n");
        while(time_to_sleep){
            time_to_sleep = sleep(time_to_sleep);
            signal(SIGUSR1, childprocess);
        }
    }
    return 0;
    }

我以这种方式编辑了我的程序:

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

void fatherprocess(int mysignal, int fatherpid){
    if (mysignal == SIGUSR1) {
        printf("ACCESS GRANTED!\n");
        kill(fatherpid, SIGUSR1);
        exit(0);
    }

    if (mysignal == SIGUSR2){
        printf("ACCESS DISCARDED! More than 3 tentatives!\n");
        kill(fatherpid, SIGUSR2);
        exit(2);
    }

}


void childprocess(int mysignal, int childpid){
    if (mysignal == SIGUSR1) {
        printf("TIMEOUT\n");
        kill(childpid, SIGUSR1);
        exit(1);
    }
}


int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[] = "test", password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;

fatherpid = getpid();
childpid = fork();

if (childpid == 0) {
    printf("Child Process waiting for a password\n");
    while (1){
        if (i < 3) {
            printf("Enter Password: ");
            scanf("%s", enteredpassword);
            if (strcmp(enteredpassword, password) == 0)
                fatherprocess(SIGUSR1, fatherpid);
        } else {
            fatherprocess(SIGUSR2, fatherpid);
            exit(1);
        }
        i++;
    }
} else {
    printf("Father Process\n");
    while(time_to_sleep){
        time_to_sleep = sleep(time_to_sleep);
        childprocess(SIGUSR1, childpid);
    }
}
return 0;
}

现在效果很好,但我不知道我是否尊重练习文本。

【问题讨论】:

  • 这是完整的代码吗?你还没有安装信号处理程序。
  • 它不完整,因为我不知道如何设置信号处理程序:(你能帮我吗?
  • 我需要使用 kill 系统调用而不是信号吗?
  • 是的,你需要使用kill()系统调用。您还需要使用sigaction()(首选)或signal()(不太首选)来处理信号。由于您没有调用sigaction()signal(),因此您的代码显然不正确。
  • 如您所见,我尝试在第一个代码块中调用 signal(),但似乎它从未调用过那些处理程序,我不知道为什么。因此,唯一有效的策略是在第二个区块中,但正如你所说,它并不完全正确。

标签: c signals fork system-calls


【解决方案1】:

正如 cmets 中提到的(由 Jonathan Leffler),您需要使用 kill() 系统调用(发送信号)并使用像 sigaction() 这样的调用注册信号处理程序。我已将这两个调用链接到提供有关它们的附加信息的在线手册页。

这里有一些代码演示了如何使用这些代码来实现您的既定目标。您仍然需要为所需的提示和可接受的输入字符串等内容添加/修改代码。请注意,我并不是说这是最好的方法,只是它是如何完成它的一个例子(它为我编译和工作):

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

static void get_password(char* buf, int maxbuf)
{
    fgets(buf, maxbuf, stdin);
}

static int is_password_correct(char* buf)
{
    return buf[0] == 'a';
}

volatile int got_signal = 0;
volatile int child_signal = 0;

static void parent_sig_handler(int signum)
{
    if (!got_signal)
    {
        got_signal = signum;
        printf("parent_sig_handler: got sig %d\n", signum);
    }
}

static void child_sig_handler(int signum)
{
    if (!child_signal)
    {
        child_signal = signum;
        printf("child_sig_handler: got sig %d\n", signum);
    }
}

int main()
{
    struct sigaction act;
    sigfillset(&act.sa_mask);
    act.sa_handler = parent_sig_handler;
    sigaction(SIGALRM, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);

    pid_t child_pid = fork();
    if (child_pid == -1)
    {
        perror("error forking");
        exit(3);
    }
    if (child_pid == 0)
    {
        printf("child running\n");
        act.sa_handler = child_sig_handler;
        sigaction(SIGUSR1, &act, NULL);
        pid_t parent_pid = getppid();
        for (int i = 0; i < 3; ++i)
        {   
            char passwd[64];
            passwd[0] = '\0';
            get_password(passwd, sizeof(passwd));
            if (is_password_correct(passwd))
            {       
                kill(parent_pid, SIGUSR1);
                exit(0);    
            }       
        }   
        kill(parent_pid, SIGUSR2);
        exit(2);
    }

    printf("parent running\n");
    alarm(30); /* sets parent up to receive a SIGALRM signal in 30 seconds */
    sigset_t sigmask;
    sigemptyset(&sigmask);
    while (!got_signal)
    {
        sigsuspend(&sigmask);
    }

    switch (got_signal)
    {
        case SIGALRM:
            kill(child_pid, SIGUSR1);
            exit(1);
        case SIGUSR1:
            exit(0);
        case SIGUSR2:
            exit(2);
        default:
            exit(3);
    }
    exit(3);
}

【讨论】:

    猜你喜欢
    • 2012-02-02
    • 1970-01-01
    • 2016-03-20
    • 2015-12-18
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    相关资源
    最近更新 更多