我们当前的项目基于通过包含滚动来扩展more
。为此,必须在一定时间内设置定时器间隔。我不确定的部分是报警信号的循环应该在哪里。我看到的所有示例都在main中有定时器值,然后在无限循环中通过pause()
显式调用信号处理程序。
我的代码有点不同,因为功能要求就像
print first screen of text after getting terminal dimensions
print prompt
if prompt = space, print another screen of text //WORKS
if prompe = q, restore original terminal settings & quit program //WORKS
if prompt = ENTER, initialize scroll at 1 line every 2 seconds //DOESN'T WORK
if prompt == f/s, increase/decrease scroll speed by 20% //DOESN'T WORK
读入缓冲区,文件指针和itimerval结构都是全局变量,以避免通过一系列函数作为参数传递。
该计划的主要功能是
void processInput(FILE *fp){
void printLine(int); //prints a single line of text
signal(SIGPROF, printLine);
int c;
//print first screen of text, check for more text to display
info(); //print prompt at bottom of screen
FILE *fterm= fopen("/dev/tty", "r");
while ((c=getc(fterm)) != EOF){
if (c== '\n'){
setTimer(2);
//four more conditionals like this in basic similarity
}
}
我的setTimer函数的基本间隔为2秒,并根据用户的f / s输入按正/负20%进行更改。
void setTimer(int direction){
int speed=2000000; //2 seconds
int change= 400000; //400 milliseconds, 20% of 2 seconds
if (direction == 1) //slow down by 20%
speed+= change;
if (direction == 0)
speed -= change;
timer.it_value.tv_sec=2;
timer.it_value.tv_usec=0;
timer.it_interval.tv_sec=0;
timer.it_interval.tv_usec= speed;
setitimer(ITIMER_PROF, &timer, NULL);
}
第一个问题:我应该使用SIGALRM还是SIGPROF,并相应地改变ITIMER_XXXX变量?
其次,我应该在哪里放入触发信号的循环?我试过了
while(1)
pause();
在几个条件中,但它具有停止执行和忽略任何输入的效果。
答案 0 :(得分:1)
如果不了解您的要求的详细信息,您无法更轻松地使用此功能 select()?
将初始选择超时设置为2秒并根据f / s输入进行调整,同时如果在超时之前有任何标准输入,则处理它。
或多或少有效的概要:
int retval;
fd_set rfds;
int input = fileno(fterm);
struct timeval tv, delay;
delay.tv_sec = 2;
delay.tv_usec = 0;
while (true)
{
FD_ZERO(&rfds);
FD_SET(input, &rfds);
tv.tv_sec = delay.tv_sec;
tv.tv_usec = delay.tv_usec;
retval = select(input + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
perror("select()");
else
if (retval)
{
if (FD_ISSET(input, &rfds))
{
command = readInput(...);
switch(command)
{
case 'q' ... cleanup & quit
case 's' ... calc 20% off delay values
case etc ...
case default...error handling
}
}
}
else //timeout
printLine();
}
答案 1 :(得分:1)
使用pause()
是危险的,因为它不是原子操作......操作系统可能会中断您的程序,导致您“丢失”信号的到来。此外,当pause()
由于信号到达而返回时,它只会再次调用pause()
。这意味着你将不得不在信号处理程序中完成所有工作,这可能不是最好的事情,即如果你在下一个信号关闭时进入信号处理程序,你可以最终得到如果您没有计划进行此类活动,那么会出现一些不可预测的行为。
更好的方法是做以下事情:
1)设置一个信号掩码,在程序开始时阻止SIGPROF
2)使用sigwait()
而不是使用信号处理程序来完成繁重的工作,而是使用包含SIGPROF掩码的sigset_t
进行设置。
3)按以下方式设置程序的主流程:
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigprocmask(SIG_BLOCK, &sigset, NULL); //block the SIGPROF signal
//process your input
//if you need to, initialize your timer and set it to go off
while(SOME_FLAG_IS_TRUE) //maybe this loops forever ... depends on what you want?
{
sigwait(&sigset, &signal_num);
if (signal_num != SIGPROF)
continue;
//process input ...
//... setup new interval timer with correct timeout ...
//... repeat loop and/or exit loop or set flag to exit loop
}
这应始终捕获来自间隔定时器的信号,因为sigwait()将在等待信号到达您的进程后正确返回,并且SIGPROF信号始终被阻止,这意味着您不能“丢失”信号。相反,至少其中一个将排队等待下一次调用sigwait()
,以防万一你在你的while循环中处理某些东西时到达。
希望这有帮助,
杰森