2011-11-02 14 views
13

Estoy usando una tubería para comunicarme entre dos procesos en Gnu/Linux. El extremo de recepción cierra el conducto mientras que el extremo de envío todavía está tratando de enviar datos. Aquí hay un código que emula la situación.¿Cómo evito SIGPIPE cuando uso boost :: asio?

#include <unistd.h>                
#include <boost/asio.hpp>               

int main()                  
{                     
    int pipe_fds[2];            
    if(::pipe(pipe_fds) != 0) return 1;           
    // close the receiving end 
    ::close(pipe_fds[0]); 

    boost::asio::io_service io;            
    boost::asio::posix::stream_descriptor sd(io, pipe_fds[1]);  
    boost::system::error_code ec;             
    sd.write_some(boost::asio::buffer("blah"), ec); 

    return 0;                  
} 

Cuando lo ejecuto obtengo un SIGPIPE; situación clásica, lo sé. Sin embargo, veo que boost::asio::error::basic_errors tiene un valor de broken_pipe. Esperaría que se devuelva en el error_code sin que se genere una señal.

¿Se puede hacer esto sin crear un controlador SIGPIPE para mi proceso? Por ejemplo, ¿hay alguna opción de configuración para impulsar :: asio que me falta? Tal vez algo que permita MSG_NOSIGNAL en la implementación?

+1

1 para el reproductor –

Respuesta

7

instalar un controlador de señal de ignorar SIGPIPE si desea ver el código apropiado error_code

y compilar

#include <unistd.h> 
#include <iostream> 
#include <boost/asio.hpp> 


int main(int argc, const char** argv) 
{ 
    bool ignore = false; 
    if (argc > 1 && !strcmp(argv[1], "ignore")) { 
     ignore = true; 
    } 
    std::cout << (ignore ? "" : "not ") << "ignoring SIGPIPE" << std::endl; 

    if (ignore) { 
     struct sigaction sa; 
     std::memset(&sa, 0, sizeof(sa)); 
     sa.sa_handler = SIG_IGN; 
     int res = sigaction(SIGPIPE, &sa, NULL); 
     assert(res == 0); 
    } 

    int pipe_fds[2]; 
    if(::pipe(pipe_fds) != 0) return 1; 
    // close the receiving end 
    ::close(pipe_fds[0]); 

    boost::asio::io_service io; 
    boost::asio::posix::stream_descriptor sd(io, pipe_fds[1]); 
    boost::system::error_code ec; 
    sd.write_some(boost::asio::buffer("blah"), ec); 

    if (ec) { 
     std::cerr << boost::system::system_error(ec).what() << std::endl; 
    } else { 
     std::cout << "success" << std::endl; 
    } 

    return 0; 
} 

[email protected] ~> g++ pipe.cc -lboost_system -lboost_thread-mt 
[email protected] ~> 

plazo

[email protected] ~> ./a.out 
not ignoring SIGPIPE 
[email protected] ~> echo $? 
141 
[email protected] ~> ./a.out ignore 
ignoring SIGPIPE 
Broken pipe 
[email protected] ~> 

La razón de este comportamiento es en el write(2) man page

EPIPE

fd está conectado a un tubo o casquillo cuyo extremo lectura está cerrada. Cuando sucede, el proceso de escritura también recibirá una señal SIGPIPE. (Por lo tanto, se considera el valor de retorno de escritura sólo si el programa de captura, bloques o ignora esta señal.)

énfasis añadido por mí.

+0

1 buena respuesta completa como siempre :) – Ralf

+0

Muy mal, no me di cuenta de la aplicación estaba usando escritura. Esperaba que usaran enviar y podría permitir pasar el indicador MSG_NOSIGNAL. Gracias por el código de ejemplo. – kalaxy

+0

@kalaxy puede usar MSG_NOSIGNAL con enviar –

3

SIGPIPE es generado por el sistema operativo cuando un extremo de un tubo no está conectado; no se puede evitar con boost :: asio. Sin embargo, puedes simplemente ignorar la señal y el resto debería cuidarse solo.

2

signal_init tiene hacerlo en el archivo boost/asio/detail/signal_init.hpp

+1

Pero parece hacerlo solo para algunas plataformas. Desafortunadamente, notablemente no se incluye desde Boost 1.55.0 en Linux y OS X. – eregon

Cuestiones relacionadas