0

我在处理计算机上运行的两个进程之间的信号时遇到问题。scheduler.c 正在发送信号,而 producer.c 正在接收它们。生产者应该打印“Printing n”,其中每次接收到 SIGUSR1 时 n 都会增加 1。我曾尝试同时使用信号和 sigaction 来处理信号,但它们都不适合我。

调度程序.c:

/*
 * scheduler.c
 */


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

int n = 1;


int main(int argc, char *argv[])
{
    int a = 0; // This variable will be used for the switch later

    // Check to ensure correct number of command line arguments
    if(argc != 2){
        printf("Usage error. Wrong number of arguments\n");
        return 1;
    }

    // Grab PID of producer.c
    int producer_pid = atoi(argv[1]);       

    while(1){
        printf("Choose an Option: \n");
        printf("1. Request_Production\n");
        printf("2. Stop_Producer\n");
        printf("3. Stop_Scheduler\n");
        scanf("%d", &a);

        switch( a ) 
        {
            case 1:
                kill(producer_pid, 16);     //Send SIGUSR1 to producer.c
                break;

            case 2:
                kill(producer_pid, 2);      //Send SIGINT to producer.c
                break;

            // Successfully exit program
            case 3:
                return 0;

            // Invalid Choice
            default :
                printf("Invalid choice\n");
        }
    }
}

生产者.c:

/*
 * producer.c
 */

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

int n = 1;

void sigusr1(int signo)
{

    printf("Producing %d", n);
    n++;
}


int main()
{


    struct sigaction act;
    sigset_t block_mask;
    sigfillset(&block_mask);
    act.sa_handler = sigusr1;
    act.sa_mask = block_mask;
    act.sa_flags = 0;

    if(sigaction(SIGUSR1, &act, NULL) == 0){
        printf("success");
    }


    while(1) {

        sleep(2);
        fflush(stdout);
    }

}
4

2 回答 2

2

此代码适用于我(在 Mac OS X 10.7.5 上):

生产者.c

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

static volatile sig_atomic_t n = 0;

static void sigusr1(int signo)
{
    n += signo / SIGUSR1;
}

int main(void)
{
    struct sigaction act;
    sigset_t block_mask;
    sigfillset(&block_mask);
    act.sa_handler = sigusr1;
    act.sa_mask = block_mask;
    act.sa_flags = 0;

    if (sigaction(SIGUSR1, &act, NULL) == 0)
    {
        printf("success %d\n", (int)getpid());
        while (1)
        {
            pause();
            printf("Producer: %d\n", n);
            fflush(stdout);
        }
    }
}

调度程序.c

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

int main(int argc, char *argv[])
{
    int a = 0; // This variable will be used for the switch later

    // Check to ensure correct number of command line arguments
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s pid\n", argv[0]);
        return 1;
    }

    // Grab PID of producer.c
    int producer_pid = atoi(argv[1]);       

    while(1)
    {
        printf("Choose an Option: \n");
        printf("1. Request Production\n");
        printf("2. Stop Producer\n");
        printf("3. Stop Scheduler\n");
        scanf("%d", &a);

        switch (a) 
        {
            case 1:
                if (kill(producer_pid, SIGUSR1) != 0)
                    fprintf(stderr, "Failed to send signal %d to %d\n", SIGUSR1, producer_pid);
                break;

            case 2:
                if (kill(producer_pid, SIGTERM) != 0)
                    fprintf(stderr, "Failed to send signal %d to %d\n", SIGTERM, producer_pid);
                break;

            // Successfully exit program
            case 3:
                return 0;

            // Invalid Choice
            default :
                fprintf(stderr, "Invalid choice (%d)\n", a);
                break;
        }
    }
}

样本输出

$ (./producer &)
$ success 40119
$ ./scheduler 40119
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 1
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 2
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 3
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 4
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 5
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 6
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 7
1
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 8
2
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
1
Failed to send signal 30 to 40119
Choose an Option: 
1. Request Production
2. Stop Producer
3. Stop Scheduler
3
$

发生了什么变化?

各种变化,但关键是:

  1. 确保输出消息以换行符结尾。
  2. 变成n一个volatile sig_atomic_t变量;这就是 C 标准所说的您可以在信号处理程序中访问的内容。
  3. 在生产者中有主循环,pause()然后打印。系统调用仅在pause()被信号中断时返回。
  4. 在调度程序中也使用符号信号名称。
  5. 让调度程序发送SIGTERM而不是SIGINT终止生产者。 如果生产者在后台运行,它会忽略中断。
  6. 让调度程序识别kill()调用何时失败。
  7. 让生产者识别其 PID。

我已经从文件标题中删除了多余的标题。

信号处理程序中的有趣signo / SIGUSR1之处避免了未使用参数的警告;它没有其他用途。如图所示,程序在以下条件下干净地编译:

gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition scheduler.c -o scheduler  
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition producer.c -o producer

这是使用 GCC 4.7.1。

于 2013-02-15T05:18:02.263 回答
1

一句话:

有些函数是安全的,有些函数是不安全的,不能从信号处理程序中调用。

printf不能从信号处理程序中调用。write另一方面是安全的。

该列表由 POSIX-1 指定,但详细信息可能因操作系统而异。对于 Linux,您将在 signal(7) 中找到该列表:

http://linux.die.net/man/7/signal

于 2013-02-15T04:39:26.387 回答