Unblock synchronous read on boost::asio::serial_po

2019-06-18 04:27发布

问题:

I have a boost::thread which performs synchronous reads on a boost::asio::serial_port. When I destroy an instance of the class which contains both, I want the thread to end gracefully even if its blocked in a read call. How can I do this?

Looking at the docs, I tried cancel, but it works only for asynchronous reads/writes. Then I tried close, but I got an exception and it wasn't the kind you can recover from. Perhaps using send_break or native_handle? (this is Windows and portability's not critical)

Update: I also tried to stop the io_service I passed to the serial port object's constructor, but the read wasn't unblocked.

Edit: The exception is actually "catchable", but I'd hate to put a try/catch block inside a destructor, and refactoring the code to do the shutdown process outside the destructor would trigger lots of changes in upper layers. So I'd only go for this solution if some Boost authority says there is no other way.

回答1:

There is no way to unblock the synchronous read as you ask to.

There are two options:

  • close/shutdown the port and catch an exception, which was raised
  • use asynchronous reads and cancel them, when you shutdown your application

The first one, of course, is not a good idea, because you cannot distinguish terminating application from error.



回答2:

On close, you say that you get an exception that 'wasn't the kind you can recover from'.

What does this mean?

The solution seems to be to catch the exception. Why cannot you do that?

For the case when you want to distinguish between an error and program termination, set a flag on program termination before the close. In the exception handler ( catch ) check the flag. If set, handle as program termination, else handle as error.

You say that you do not wish to place a try/catch block inside a destructor. This seems like an odd prejudice to me, but OK there are other ways.

  1. You can allow the exception to propagate all the way to the topmost catch block that surrounds all your code, and handle it there. ( You do have such a try/catch block protecting your entire application, of course :-)

  2. Other ways are also possible ... but boss just dropped by