Suggestion about using Signals2
Hi,
I need some help on using signals2 in my app, I hope to explain my
problem well.
I have a thread that reads from the RS232:
void SerialPort::reading()
{
... read...
if (data_available) signal_OnData;
}
the signal_OnData is:
typedef boost::signals2::signal
Daniele Barzotti wrote:
I have a thread that reads from the RS232:
void SerialPort::reading() { ... read... if (data_available) signal_OnData; }
the signal_OnData is:
typedef boost::signals2::signal
_signal_void; _signal_void signal_OnData; And I connect it to a method MyUserClass::OnDataReceived()
Into this method (MyUserClass::OnDataReceived) I need to re-send some data to RS232, but the SerialPort::reading thread is locked because it's waiting the OnDataReceived ends..
In fact, when the methods OnDataReceived ends, I receive data again.
I have solve this issue creating a new thread to manage data: MyUserClass::OnDataReceived() { // Create New Thread try { _read_thread_ptr.reset( new boost::thread(boost::bind(&MyUserClass::ManageData, this)) ); } catch (boost::thread_resource_error e) { // Failed to create the new thread return; } } But another problem is raised: when I receive 2 command one after other quickly, I miss the second, so... Is there a method to launch a signal directly into another thread? Something like: boost::thread(boost::bind(signal_OnData, ptrToObj)) thanks in advance! Daniele.
But another problem is raised: when I receive 2 command one after other quickly, I miss the second, so...
Is there a method to launch a signal directly into another thread? Something like:
boost::thread(boost::bind(signal_OnData, ptrToObj))
I'm not sure I understand your issue, but anyway, in such kind of task you can consider using boost.asio. Using asio::io_service::post you can conveniently post functors between different threads, without the need for explicit locking.
Igor R ha scritto:
But another problem is raised: when I receive 2 command one after other quickly, I miss the second, so...
Is there a method to launch a signal directly into another thread? Something like:
boost::thread(boost::bind(signal_OnData, ptrToObj))
I'm not sure I understand your issue, but anyway, in such kind of task you can consider using boost.asio. Using asio::io_service::post you can conveniently post functors between different threads, without the need for explicit locking.
Hi Igor, thanks for the reply... You mean using asio::io_service::post instead of signals or using asio::serial_port instead of my serial classes? If you have a minimal code snippet I will grateful! Daniele.
You mean using asio::io_service::post instead of signals or using asio::serial_port instead of my serial classes?
No I just mean using asio::io_service as a functor queue processor, but if you use asio you definitely can benefit from its serial_port class as well.
If you have a minimal code snippet I will grateful!
If you want to see a working code with asio, you can refer to one the asio examples, but in general I mean the following scheme (pseudo-code!): // encapsulates yours or asio i/o object, like socket, serial_port etc. class connection : public boost::enable_shared_from_this<connection> { public: connection(boost::asio::io_service &io) : io_(io) {} public: void send(data_type data) { // since send() might be called from a client thread, do not process the data here, // just post it to the io_ thread(s), where the data will be delivered to the socket/port io_.post(&connection::do_send, shared_from_this(), data); } private: // this method is always called within io_ thread(s) void data_received() { //issue the signal } void do_send(data_type data) { // send the data } }; // listens to the connection; class data_receiver { void data_received(data_type data) { doSomething(); connection->send(somethingElse); } };
Igor R ha scritto:
If you want to see a working code with asio, you can refer to one the asio examples, but in general I mean the following scheme (pseudo-code!):
// encapsulates yours or asio i/o object, like socket, serial_port etc. class connection : public boost::enable_shared_from_this<connection> { public: connection(boost::asio::io_service &io) : io_(io) {} public: void send(data_type data) { // since send() might be called from a client thread, do not process the data here, // just post it to the io_ thread(s), where the data will be delivered to the socket/port io_.post(&connection::do_send, shared_from_this(), data); } private: // this method is always called within io_ thread(s) void data_received() { //issue the signal } void do_send(data_type data) { // send the data } };
// listens to the connection; class data_receiver { void data_received(data_type data) { doSomething(); connection->send(somethingElse); } };
Thanks a lot for your suggestions, Igor!! Cheers, Daniele.
Igor R ha scritto:
// encapsulates yours or asio i/o object, like socket, serial_port etc. class connection : public boost::enable_shared_from_this<connection> { public: connection(boost::asio::io_service &io) : io_(io) {}
Hi Igor, is there a reason to create the io_service outside the class? Can I create an instance of it directly into the connection object?
public: void send(data_type data) { // since send() might be called from a client thread, do not process the data here, // just post it to the io_ thread(s), where the data will be delivered to the socket/port io_.post(&connection::do_send, shared_from_this(), data); } private: // this method is always called within io_ thread(s) void data_received() { //issue the signal } void do_send(data_type data) { // send the data } };
In your example you use io_.post() into the send method, why you don't use it also in the data_received? Thanks! Daniele.
is there a reason to create the io_service outside the class? Can I create an instance of it directly into the connection object?
Yes, you can. But usually you don't want to create io_service for every connection or for every "active object" (you can use a single io_service for all these objects or use io_service-per-cpu strategy - see asio examples for details), that's why that you might want to manage io_service(s) creation outside these objects.
In your example you use io_.post() into the send method, why you don't use it also in the data_received?
Well, I meant that it's the handler of one of the asio standard async. read methods, like this: class connection : ... { //... asio::serial_port serial_port_; void receive() { serial_port_.async_read_some(myBuffer, bind(&connection::data_received, shared_from_this())) } void data_received() { // always executed in io_service thread(s) } }; But if you use some other i/o object to communicate with socket/serial port, and utilize io_service just to process functors asyncronously, and you wish to notify connection user from io_service thread - then you can use the same technique there. It's just matter of your design. Anyway, I recommend you to look at the asio tutorial and examples, to find out some common usage scenarios and design proposals.
Igor R ha scritto:
is there a reason to create the io_service outside the class? Can I create an instance of it directly into the connection object?
Yes, you can. But usually you don't want to create io_service for every connection or for every "active object" (you can use a single io_service for all these objects or use io_service-per-cpu strategy - see asio examples for details), that's why that you might want to manage io_service(s) creation outside these objects.
Ok, now I've understand! I'm sorry but it's my first approach to asio!
But if you use some other i/o object to communicate with socket/serial port, and utilize io_service just to process functors asyncronously, and you wish to notify connection user from io_service thread - then you can use the same technique there. It's just matter of your design. Anyway, I recommend you to look at the asio tutorial and examples, to find out some common usage scenarios and design proposals.
Yes, this is exactly what I have to do. I will looking into the tutorials!! Just one last thing.. I've tried to to something like this (where signal_OnData is a signal): void SerialPort::reading() { .... data available... //signal_OnData(); _io.post( boost::bind(&SerialPort::Post_OnData, this) ); } void SerialPort::Post_OnData() { signal_OnData(); }; but the SerialPort::Post_OnData is not called, is this my design wrong? Thanks very mutch for your support!!! Daniele.
Just one last thing..
I've tried to to something like this (where signal_OnData is a signal):
void SerialPort::reading() { .... data available... //signal_OnData(); _io.post( boost::bind(&SerialPort::Post_OnData, this) ); }
void SerialPort::Post_OnData() { signal_OnData(); };
but the SerialPort::Post_OnData is not called, is this my design wrong?
I guess that your io_service is not running, so noone processes its queue. You have to call io_service::run function, it's kindof "message loop" of io_service: http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/tutorial/tutdaytime...
Igor R ha scritto:
Just one last thing..
I've tried to to something like this (where signal_OnData is a signal):
void SerialPort::reading() { .... data available... //signal_OnData(); _io.post( boost::bind(&SerialPort::Post_OnData, this) ); }
void SerialPort::Post_OnData() { signal_OnData(); };
but the SerialPort::Post_OnData is not called, is this my design wrong?
I guess that your io_service is not running, so noone processes its queue. You have to call io_service::run function, it's kindof "message loop" of io_service: http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/tutorial/tutdaytime...
Yes, I've called the _io.run() into my SerialPort constructor, but I think it end immediately because it has no work to do!! I'm reading docs and articles but one thing I can't understand... In my SerialPort class the reading method is called in a separate thread when I open the device and it doesn't return until I stop it: _thread.reset( new boost::thread( boost::bind(&SerialPort::reading, this)) ); using asio I think I have to 'bind' it to io_service::run so when I call _io.run() it call SerialPort::reading, but how?! Cheers, Daniele.
Yes, I've called the _io.run() into my SerialPort constructor, but I think it end immediately because it has no work to do!!
Yes, if the io_service has no work, its main loop exits. If you want it to keep running without "real" work, you can associate io_service with asio::work object (see examples).
In my SerialPort class the reading method is called in a separate thread when I open the device and it doesn't return until I stop it:
_thread.reset( new boost::thread( boost::bind(&SerialPort::reading, this)) );
using asio I think I have to 'bind' it to io_service::run so when I call _io.run() it call SerialPort::reading, but how?!
If reading() is the thread function that performs actual i/o on a serial port, certainly you can't associate that thread with io_service::run. But you can start another thread for io_service(s). By the way, wouldn't it be more simple and robust to use convenient asio async. i/o objects, instead of trying to mix the asio and your own approaches?
participants (2)
-
Daniele Barzotti
-
Igor R