等待信号,然后继续执行 [英] Wait for signal, then continue execution
问题描述
我正在尝试制作一个暂停其执行直到信号到达的程序.然后,在信号到达后,我只希望我的代码从原来的位置继续执行.我不希望它执行任何函数处理程序.有没有简单的方法可以做到这一点?我已经苦苦挣扎了一个星期左右,在这里和那里阅读,并且没有设法获得完整的可操作代码.
I am trying to make a program that suspends its execution until a signal arrives. Then, after the signal arrives I just want my code to continue its execution from where it was. I don't want it to execute a function handler or whatsoever. Is there a simple way of doing this? I have been struggling for a week or so, reading here and there, and didn't manage to get a fully operative code.
尤其是,我希望主程序创建一个线程,以等待某个特定事件的发生(例如,用户已向stdin输入了一些数据).同时,主程序正在执行某项操作,但有时会暂停执行直到收到信号为止.
In particular, I want the main program to create a thread that waits for some particular event to happen (e.g., a user has input some data to stdin). Meanwhile, the main program is doing something but at some point it suspends its execution until it receives a signal.
信号可能来自线程,因为它已检测到事件,或者可能是由于超时引起的,因为我没有希望它永远等待.
The signal may come from the thread because it has detected the event or it may be due to a timeout because I don't want it to wait for ever.
我已经编写了一些代码,但是无法正常工作...
I have made some code but it does not work as expected...
/*
* This code SHOULD start a thread that gets messages from stdin.
* If the message is a "quit", the thread exits. Otherwise it raises
* a signal that should be caught by the main program.
* The main program simply waits for the message unless a timer of
* 5.5 seconds expires before receiving the signal from the thread.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <signal.h>
#define BSIZE 100 /* Buffer size */
sigset_t mask;
pthread_t tid;
//struct itimerval timervalue;
int milisec = 5500; /* Timeout: 5,5 seconds */
int end = 0;
char buffer[BSIZE];
//Function prototypes
void init(void);
void * thread_job(void *);
void message_rcvd(void);
void wait_for_message_or_timeout(void);
int start_timer(struct itimerval, int);
int stop_timer(struct itimerval);
void on_signal(int);
// MAIN: Wait for message or timeout
int main(int argc, char ** argv) {
init();
while(!end){
wait_for_message_or_timeout();
if(!end)
printf("Message received [%s]\n", buffer);
}
return 0;
}
// INIT: Initializes the signals that the program will wait for
// and creates a thread that will eventually generate a signal
void init()
{
/* Init the signals I want to wait for with sigwait() */
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, NULL);
//signal(SIGUSR1, SIG_IGN);
signal(SIGUSR1, on_signal);
/* Create the thread and put it to work */
pthread_t tid;
pthread_create(&tid, NULL, thread_job, NULL);
}
void on_signal(int signum){
printf("on_signal\n");
}
// THREAD CODE -------------
// THREAD JOB: When the user inputs a message, it passes the message
// to the main thread by invoking message_rcvd()
void * thread_job(){
int end = 0;
while(!end){
printf("Input message:");
if (fgets(buffer, BSIZE, stdin) != NULL)
message_rcvd();
}
}
// MESSAGE RECEIVED: If message is not equal to "quit" raise a signal
void message_rcvd(){
if(strcmp(buffer, "quit") == 0){
exit(0);
}else{
printf("Going to raise SIGUSR1...");
if(raise(SIGUSR1) == 0)
printf("raised!\n");
}
}
// WAIT: Should wait for signal SIGUSR1 for some time
void wait_for_message_or_timeout(){
int sigid;
struct itimerval t;
/* Set a timer to prevent waiting for ever*/
printf("Setting timer...\n");
start_timer(t, milisec);
/* Put the process to wait until signal arrives */
sigwait(&mask, &sigid);
switch(sigid){
case SIGUSR1:
printf("Received SIGUSR1: Message avaible!\n");
break;
case SIGALRM:
printf("Received SIGALRM: Timeout\n");
end = 1;
break;
default:
printf("Unknown signal received\n");
break;
}
printf("Stopping timer...\n");
/* Stop timer */
stop_timer(t);
}
// START TIMER: I don't want the timer to cause the execution
// of a handler function
int start_timer(struct itimerval timervalue, int msec)
//int start_timer(int msec)
{
timervalue.it_interval.tv_sec = msec / 1000;
timervalue.it_interval.tv_usec = (msec % 1000) * 1000;
timervalue.it_value.tv_sec = msec / 1000;
timervalue.it_value.tv_usec = (msec % 1000) * 1000;
if(setitimer(ITIMER_REAL, &timervalue, NULL))
{
printf("\nsetitimer() error\n");
return(-1);
}
return(0);
}
// STOP TIMER:
int stop_timer(struct itimerval timervalue)
//int stop_timer()
{
timervalue.it_interval.tv_sec = 0;
timervalue.it_interval.tv_usec = 0;
timervalue.it_value.tv_sec = 0;
timervalue.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL, &timervalue, NULL))
{
printf("\nsetitimer() error\n");
return(-1);
}
return(0);
}
这是此代码的典型执行.
Here is a typical execution of this code.
./signaltest
Setting timer...
Input message:hello
Going to raise SIGUSR1...raised!
Input message:friend
Going to raise SIGUSR1...raised!
Input message:Received SIGALRM: Timeout
Stopping timer...
如您所见,信号SIGUSR1发出,sigwait解除阻塞.但是,在发出信号后,该代码似乎没有继续. (请注意,我不需要信号处理程序,而只是出于调试目的而添加了.我已经用sigprocmask
阻止了它的执行.)
As you can see, the signal SIGUSR1 is being raised and sigwait is being unblocked. However, the code seems does not continue after the signal has been raised. (Note that I don't need a signal handler but I just added for the debugging purposes. I have blocked its execution with sigprocmask
)
为什么SIGUSR1取消阻止sigwait,但是执行不从那里继续?有没有一种方法可以使它在取消阻止后继续运行?这似乎适用于SIGALRM,但为何不适用于SIGUSR1?
正如我说的,我一直在研究大量的stackoverflow问题,在线howto,并尝试了不同的系统调用(例如,pause,sigsuspend),...却找不到解决此问题的方法:-(
As I said, I have been looking at tons of stackoverflow questions, online howto's, tried with different system calls (e.g., pause, sigsuspend), ... but couldn't find a way to solve this :-(
如果您想知道为什么不通过不使用线程来简化此代码,是因为这实际上不是我要实现的代码,而只是一个使我的问题更加清楚的简单示例.我实际上是在尝试实现网络协议API,类似于我自己的协议的套接字API.
If you are wondering why I am not doing this code much simpler by not using a thread is because this is not actually the code I am implementing but just a simpler example to make my question more clear. I am actually trying to implement a network protocol API, similar to the sockets API for my own protocol.
预先感谢
推荐答案
SIGUSR1
信号没有到达您认为的位置.
The SIGUSR1
signal isn't going where you think it is.
在多线程程序中,raise
函数将信号发送到当前线程,在本例中为thread_job
线程.所以主线程永远看不到信号.
In a multithreaded program, the raise
function sends a signal to the current thread, which is the thread_job
thread in this case. So the main thread never sees the signal.
您需要保存主线程的线程ID,然后使用pthread_kill
向该线程发送信号.
You need to save off thread ID of the main thread, then use pthread_kill
to send a signal to that thread.
添加新的全局变量:
pthread_t main_tid;
然后在开始新线程之前在
Then populate it in your init
function before starting the new thread:
void init()
{
main_tid = pthread_self();
...
然后在message_rcvd
中,使用pthread_kill
:
if(pthread_kill(main_tid, SIGUSR1) == 0)
printf("raised!\n");
此外,删除thread_job
中end
的定义,并删除init
中tid
的定义.这些定义掩盖了同名的全局变量.
Also, remove the definition of end
in thread_job
, and remove the definition of tid
in init
. These definitions mask the global variables of the same name.
示例输出:
Setting timer...
Input message:hello
Going to raise SIGUSR1...raised!
Input message:Received SIGUSR1: Message avaible!
Stopping timer...
Message received [hello
]
Setting timer...
test
Going to raise SIGUSR1...raised!
Input message:Received SIGUSR1: Message avaible!
Stopping timer...
Message received [test
]
Setting timer...
Received SIGALRM: Timeout
Stopping timer...
这篇关于等待信号,然后继续执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!