【问题标题】:How do I call other functions with the signal function?如何用信号函数调用其他函数?
【发布时间】:2016-12-09 16:31:09
【问题描述】:

我昨天收到了一个合成器作为礼物,并且有兴趣向它写入数据。我做了这么多工作,这是一个通过一些音符进行缩放的程序。 然后我认为让它捕捉 Ctrl+C 信号并关闭会很好。 只关闭文件描述符的问题是 MIDI 设备仍然处理它给出的最后一个音符,所以我编写了静音函数,它告诉 MIDI 设备静音。这样可行。

然后我尝试让信号处理程序在退出之前使设备静音,从那以后我一直在苦苦挣扎。信号(SIGINT,intHandler);函数不会接受额外的参数。所以我想我会很聪明,并编写一个函数mySig,它调用信号函数并获取设备文件描述符和数据指针,并且能够在退出之前进行最后一次写入。

IDK,这甚至可能有效,但 mySig 函数似乎从一开始就被调用,并且从未发生缩放。

如何在使用信号函数退出程序之前调用我的静音函数?

这是我的第一个信号处理程序,我在运行linux,程序是C语言的。

#include <sys/soundcard.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static volatile int keepRunning = 1;
char* device =  "/dev/midi1";
//function headers:
void mute(int fd, char *data);
void intHandler(int dummy);
void mySig(void (*intHandler)(int dummy), int fd, char *data);

int main(void){

    unsigned int note=50;

    char data[3] = {0x90, note, 33}; //device address, note, volume
    int fd = open(device, O_WRONLY, 0);
    if( fd < 0 ){
      printf("Error: cannot open Synth %s\n", device);
      exit(1);
      }
    signal(SIGINT, intHandler);      
//      mySig(intHandler,fd,data);

while(keepRunning){
    for( note=30; note < 95; note++ ){
        data[1]=note;//change note
        write( fd, data, sizeof(data) );
        usleep(100000); 
        if(note>=89){
           note =30;
           }
        }
mute(fd,data); //mutes the data stream.
   close(fd); // close device

   return 0;
}
}
//functions:  
void mute(int fd, char *data){
    data[2]=0;//setVolume to 0
    write(fd, data, sizeof(data));
    close(fd);
    }

void mySig(void (*intHandler)(int dummy), int fd, char *data){
    printf("my Sig has been called\n");
    mute(fd,data);
    signal(SIGINT, intHandler);
    }

void intHandler(int dummy) {
    printf("my Sig has been called\n");
    keepRunning = 1;
    printf("ctrl+c was pressed, exiting\n");
    usleep(10000);
    exit(1);
}

【问题讨论】:

标签: c linux signals


【解决方案1】:

使用信号处理程序仅清除您的 keepRunning 标志。 就个人而言,我更喜欢相反的标志,如done

static volatile sig_atomic_t  done = 0;

static void done_handler(int signum)
{
    done = 1; /* Or, in Linux, done = signum. */
}

static int install_done(const int signum)
{
    struct sigaction  act;

    memset(&act, 0, sizeof act);

    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = done_handler;
    if (sigaction(signum, &act, NULL) == -1)
        return errno;

    return 0;
}

如果用户在终端中运行程序,意外关闭终端,程序会收到SIGHUP信号; Ctrl+C 导致SIGINT 信号; SIGTERM 常用于要求程序退出。所以,我个人喜欢这样做

    if (install_done(SIGINT) ||
        install_done(SIGHUP) ||
        install_done(SIGTERM)) {
        fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

早在我的main()

所有你需要做的,就是让你的循环——在我的例子中,

    while (!done) {
        /* Play notes or whatever */
    }

在循环结束后,将播放的最后一个音符静音,然后关闭设备。

认为信号只是一个请求退出,只要方便;不是要求立即退出。预计程序在收到要求它们退出的信号时会进行必要的清理。如果想要一个程序立即退出,可以随时使用SIGKILL 终止该进程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多