[boost::asio::serial_port] Calling cancel() causes Run-Time Check Failure #0 on Visual Studio 2010 SP1
This is a fatal error, there's no way to recover from it, and in release builds, a nasty message box appears. It happens when I call serial_port::cancel and Boost tries to throw some exception. The exact error is: Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention. And it seems to happen in throw_error.ipp, inside the do_throw_error method. Here's a small sample program which reproduces this: #include <boost/asio/serial_port.hpp> #include <boost/asio/read.hpp> #include <boost/thread.hpp> #include <iostream> using namespace std; BYTE g_pBuffer[128]; void ReadCompletionHandler( boost::system::error_code ec, std::size_t bytesTransferred ){ if( !ec ){ cout << "Read " << bytesTransferred << " bytes successfully" << endl; }else if( ec == boost::asio::error::operation_aborted ){ cout << "Aborted async_read_some, " << bytesTransferred << " bytes transferred" << endl; }else{ cout << "Read finished with errors: " << ec.message() << endl; } } void ReaderThread( boost::asio::serial_port* pSerialPort ){ cout << "[ReaderThread] Started reading" << endl; boost::asio::async_read( *pSerialPort, boost::asio::buffer( g_pBuffer, 5 ), ReadCompletionHandler ); cout << "[ReaderThread] Done!" << endl; } void main(){ //Tell cout not to buffer its output so output better reflects multithreaded execution std::cout.setf(std::ios::unitbuf); boost::asio::io_service ioService; boost::asio::serial_port serialPort( ioService ); string portName = "COM1"; serialPort.open( portName ); if( !serialPort.is_open() ){ cout << "Failed to open " << portName << endl; return; } cout << "Launching reader thread and io_service" << endl; boost::thread readerThread( boost::bind( ReaderThread, &serialPort ) ); ioService.run(); cout << "Sleeping..." << endl; ::Sleep( 5000 ); cout << "Woke up, cancelling pending reads" << endl; serialPort.cancel(); cout << "Waiting for reader thread to finish..." << endl; readerThread.join(); cout << "Done!" << endl; cin.get(); } Maybe I'm doing something stupid. What do you think? -- *Darío Eduardo Ramos* Meditech S.A. www.meditech.com.ar (+54) 01147603300, Interno 31 Av. Julio A. Roca 3456 Florida Oeste, Bs.As. Argentina
This is a fatal error, there's no way to recover from it, and in release builds, a nasty message box appears. It happens when I call serial_port::cancel and Boost tries to throw some exception. The exact error is:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
I couldn't reproduce this crash (Boost 1.49, MSVC10, Win7), maybe because I don't have any trafic on COM1, but any way -- asio objects are not thread-safe, so it might be unsafe to call cancel() this way. Instead, try using the following: ioService.post([&] {serialPort.cancel();}); - and see if it helps.
Are you using Windows XP? If you are it is due to Win32 API CancelIo can only cancel IO requests from the same thread as the CancelIO request itself. Vista and later has CancelIoEx which can cancel IO requests from any thread. As I remember Boost Asio Serial checks whether CancelIoEx is supported and if not will throw an exception if it determines the CancelIo request is not on the same thread as the outstanding IO request. Richard On 15 March 2012 14:21, Igor R <boost.lists@gmail.com> wrote:
This is a fatal error, there's no way to recover from it, and in release builds, a nasty message box appears. It happens when I call serial_port::cancel and Boost tries to throw some exception. The exact error is:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
I couldn't reproduce this crash (Boost 1.49, MSVC10, Win7), maybe because I don't have any trafic on COM1, but any way -- asio objects are not thread-safe, so it might be unsafe to call cancel() this way. Instead, try using the following: ioService.post([&] {serialPort.cancel();}); - and see if it helps. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Igor said:
I couldn't reproduce this crash (Boost 1.49, MSVC10, Win7), maybe because I don't have any trafic on COM1, but any way -- asio objects are not thread-safe, so it might be unsafe to call cancel() this way. Instead, try using the following: ioService.post([&] {serialPort.cancel();}); - and see if it helps. <http://lists.boost.org/mailman/listinfo.cgi/boost-users>
It definitely helps; it crashed 0 out of 10 times, which is enough for me (it crashed every time before, even without traffic). I didn't know asio objects weren't thread-safe. I need to use them in a multithreaded environment; I have a reader and a writer thread. I suppose that wrapping every call to the serial_port object inside a post message would avoid any trouble but might be too slow. Am I right? Are there some general guidelines I should follow when using asio objects in multithreaded environments? Richard said:
Are you using Windows XP? If you are it is due to Win32 API CancelIo can only cancel IO requests from the same thread as the CancelIO request itself. Vista and later has CancelIoEx which can cancel IO requests from any thread. As I remember Boost Asio Serial checks whether CancelIoEx is supported and if not will throw an exception if it determines the CancelIo request is not on the same thread as the outstanding IO request.
That makes a lot of sense, since I am indeed using XP. It also explains why using post solves the issue. Anyway, if Boost performs that check, the Runtime Check failure shouldn't happen. Could this be a bug? -- *Darío Eduardo Ramos* Meditech S.A. www.meditech.com.ar (+54) 01147603300, Interno 31 Av. Julio A. Roca 3456 Florida Oeste, Bs.As. Argentina
It definitely helps; it crashed 0 out of 10 times, which is enough for me (it crashed every time before, even without traffic). I didn't know asio objects weren't thread-safe.
It's explicitly stated in the docs: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/serial_po... (Look at the page footer.) But in this particular case, the problem certainly was CancelIo issue, rather than thread-safety one.
I need to use them in a multithreaded environment; I have a reader and a writer thread. I suppose that wrapping every call to the serial_port object inside a post message would avoid any trouble but might be too slow. Am I right?
No, i don't think it would be slow, I believe the i/o itself would be *much* slower. But in any case, making "premature optimizations" is usually a bad idea. After you profile your application performance in a real-life scenario -- you'll be able to see where the bottlenecks are and to resolve them.
Are there some general guidelines I should follow when using asio objects in multithreaded environments?
You can find the most useful approaches in asio tutorial and examples: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/tutorial.html http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/examples.html
participants (3)
-
Dario Ramos
-
Igor R
-
Richard Rowlands