昨天我收到了一个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);
}
答案 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
终止该进程。