如何使用信号功能调用其他功能?

时间:2016-12-09 16:31:09

标签: c linux signals

昨天我收到了一个Synthasizer礼物,并有兴趣为它写数据。我有这么多工作,这是一个通过一些笔记扩展的程序。 然后我认为让它抓住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);
}

1 个答案:

答案 0 :(得分: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终止该进程。