c / interrupted system call / fork vs. thread

后端 未结 2 1231
说谎
说谎 2021-01-13 17:24

I discovered an issue with thread implementation, that is strange to me. Maybe some of you can explain it to me, would be great.

I am working on something like a pro

相关标签:
2条回答
  • 2021-01-13 17:43

    EINTR does not itself indicate an error. It means that your process received a signal while it was in the sendto syscall, and that syscall hadn't sent any data yet (that's important).

    You could retry the send in this case, but a good thing would be to figure out what signal caused the interruption. If this is reproducible, try using strace.

    If you're the one sending the signal, well, you know what to do :-)

    Note that on linux, you can receive EINTR on sendto (and some other functions) even if you haven't installed a handler yourself. This can happen if:

  • the process is stopped (via SIGSTOP for example) and restarted (with SIGCONT)
  • you have set a send timeout on the socket (via SO_SNDTIMEO)

    See the signal(7) man page (at the very bottom) for more details.

    So if you're "suspending" your service (or something else is), that EINTR is expected and you should restart the call.

0 讨论(0)
  • 2021-01-13 17:44

    Keep in mind if you are using threads with signals that a given signal, when delivered to the process, could be delivered to any thread whose signal mask is not blocking the signal. That means if you have blocked incoming signals in one thread, and not in another, the non-blocking thread will receive the signal, and if there is no signal handler setup for the signal, you will end-up with the default behavior of that signal for the entire process (i.e., all the threads, both signal-blocking threads and non-signal-blocking threads). For instance, if the default behavior of a signal was to terminate a process, one thread catching that signal and executing it's default behavior will terminate the entire process, for all the threads, even though some threads may have been masking the signal. Also if you have two threads that are not blocking a signal, it is not deterministic which thread will handle the signal. Therefore it's typically the case that mixing signals and threads is not a good idea, but there are exceptions to the rule.

    One thing you can try, is since the signal mask for a spawned thread is inherited from the generating thread, is to create a daemon thread for handling signals, where at the start of your program, you block all incoming signals (or at least all non-important signals), and then spawn your threads. Now those spawned threads will ignore any incoming signals in the parent-thread's blocked signal mask. If you need to handle some specific signals, you can still make those signals part of the blocked signal mask for the main process, and then spawn your threads. But when you're spawning the threads, leave one thread (could even be the main process thread after it's spawned all the worker threads) as a "daemon" thread waiting for those specific incoming (and now blocked) signals using sigwait(). That thread will then dispatch whatever functions are necessary when a given signal is received by the process. This will avoid signals from interrupting system calls in your other worker-threads, yet still allow you to handle signals.

    The reason your forked version may not be having issues is because if a signal arrives at one parent process, it is not propagated to any child processes. So I would try, if you can, to see what signal it is that is terminating your system call, and in your threaded version, block that signal, and if you need to handle it, create a daemon-thread that will handle that signal's arrival, with the rest of the threads blocking that signal.

    Finally, if you don't have access to any external libraries or debuggers, etc. to see what signals are arriving, you can setup a simple procedure for seeing what signals might be arriving. You can try this code:

    #include <signal.h>
    #include <stdio.h>
    
    int main()
    {
        //block all incoming signals
        sigset_t signal_mask;
        sigfillset(&signal_mask);
        sigprocmask(SIG_BLOCK, &signal_mask, NULL);
    
        //... spawn your threads here ...
    
        //... now wait for signals to arrive and see what comes in ...
    
        int arrived_signal;
    
        while(1) //you can change this condition to whatever to exit the loop
        {
            sigwait(&signal_mask, &arrived_signal);
    
            switch(arrived_signal)
            {
                 case SIGABRT: fprintf(stderr, "SIGABRT signal arrived\n"); break;
                 case SIGALRM: fprintf(stderr, "SIGALRM signal arrived\n"); break;
    
                 //continue for the rest of the signals defined in signal.h ...
    
                 default: fprintf(stderr, "Unrecognized signal arrived\n");
            }
        }
    
        //clean-up your threads and anything else needing clean-up
    
        return 0;
    }
    
    0 讨论(0)
  • 提交回复
    热议问题