等待信号,然后继续执行 [英] Wait for signal, then continue execution

查看:106
本文介绍了等待信号,然后继续执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个暂停其执行直到信号到达的程序.然后,在信号到达后,我只希望我的代码从原来的位置继续执行.我不希望它执行任何函数处理程序.有没有简单的方法可以做到这一点?我已经苦苦挣扎了一个星期左右,在这里和那里阅读,并且没有设法获得完整的可操作代码.

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_jobend的定义,并删除inittid的定义.这些定义掩盖了同名的全局变量.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆