boost::asio::deadline_timer and boost::asio::io_service
Hi, I use a single thread to run 3 classes using boost::asio::deadline_timer, the timers are managed by boost::asio::io_service. I deliberately use a single thread to avoid mutex, I believe those 3 timers are called exclusively by boost::asio::io_service in a single thread, there won't be race condition to share the objects among them, is it correct? Thank you. Kind regards, - jupiter
Hi,
Does io_service create threads for running timers? My application is
running a single thread, but if io_service creates multiple threads
for running timer, I must use the mutex or atomic lock.
Thank you.
Kind regards,
- jupiter
On 9/1/19, JH
Hi,
I use a single thread to run 3 classes using boost::asio::deadline_timer, the timers are managed by boost::asio::io_service. I deliberately use a single thread to avoid mutex, I believe those 3 timers are called exclusively by boost::asio::io_service in a single thread, there won't be race condition to share the objects among them, is it correct?
Thank you.
Kind regards,
- jupiter
On 2/09/2019 13:06, JH wrote:
Does io_service create threads for running timers? My application is running a single thread, but if io_service creates multiple threads for running timer, I must use the mutex or atomic lock.
Don't top-post. As is documented, while Asio may or may not create internal threads for various purposes, it does guarantee that the I/O callback functions (including timer callbacks) are only ever called on a thread which is currently executing run() or equivalent on the same service/context. If there is only one such thread (an "implicit strand"), then you don't need locks to protect things that are only accessed from an I/O callback, even if there is more than one such callback (provided that all callbacks were registered on the same service/context). You may still need locks to protect things that are accessed from both callbacks and initiating functions (or elsewhere), unless you ensure that initiating functions delegate their concurrent work to the I/O thread via dispatch()/post().
Thanks Gavin,
On 9/2/19, Gavin Lambert via Boost
On 2/09/2019 13:06, JH wrote:
Does io_service create threads for running timers? My application is running a single thread, but if io_service creates multiple threads for running timer, I must use the mutex or atomic lock.
Don't top-post.
As is documented, while Asio may or may not create internal threads for various purposes, it does guarantee that the I/O callback functions (including timer callbacks) are only ever called on a thread which is currently executing run() or equivalent on the same service/context.
Yes, it is a single thread from my run function, there is no thread create, so that did guarantee the single thread to run the timer one by one in order as I original understanding.
If there is only one such thread (an "implicit strand"), then you don't need locks to protect things that are only accessed from an I/O callback, even if there is more than one such callback (provided that all callbacks were registered on the same service/context).
Each timer has only one callback.
You may still need locks to protect things that are accessed from both callbacks and initiating functions (or elsewhere), unless you ensure that initiating functions delegate their concurrent work to the I/O thread via dispatch()/post().
Does that mean if any callbacks to involve IO write / read, it still need locks? What about just to copy shared global buffer to own local buffers? The two timer callbacks only copy contents from one globe buffer to its own local buffer, then use own local buffer to write file, I think that should be safe, no locks need. Another timer callback is to read / write chip registers from a serial line, that looks like must either lock the global buffer or copy global buffer to a local buffer, right? Thanks Gavin.
On 2/09/2019 15:54, JH wrote:
Does that mean if any callbacks to involve IO write / read, it still need locks? What about just to copy shared global buffer to own local buffers?
The two timer callbacks only copy contents from one globe buffer to its own local buffer, then use own local buffer to write file, I think that should be safe, no locks need.
Another timer callback is to read / write chip registers from a serial line, that looks like must either lock the global buffer or copy global buffer to a local buffer, right?
It doesn't matter how many timers there are, it only matters how many I/O services/contexts you have and how many threads you're calling run() on for each service. If you're only doing things in the handlers of timer/read/write callbacks, then they're all executing on the I/O thread and so won't be called concurrently, so you don't need any locking. If you have some external code which is running on another thread and can touch the same objects (perhaps prior to calling async_write or async_wait), then those either need protection or you need to dispatch/post their work to the I/O thread instead (so that they cannot run concurrently with a callback). Bear in mind that if you're writing to that file synchronously, then it will also prevent the other callbacks from executing for however long that takes. Depending on what you're doing, that may or may not be a good thing.
On 9/2/19, Gavin Lambert via Boost
It doesn't matter how many timers there are, it only matters how many I/O services/contexts you have and how many threads you're calling run() on for each service.
Yes, three IO read / write, but only one thread. The thing I am not clear was your comment, "You may still need locks to protect things that are accessed from both callbacks". I always thought like said in document "timers may be implemented in terms of a single timer queue. The I/O services manage these shared resources", if the timers callbacks / handlers exclusively run one by one in one thread, there won't be any preambles, there won't be race conditions, why still need lock from both callbacks? I deliberately designed to use a single thread to avoid locks, the comments I still need locks in a single thread, make me to rethink and probably to redesign the single thread io_service structure I have been embraced for many years.
If you're only doing things in the handlers of timer/read/write callbacks, then they're all executing on the I/O thread and so won't be called concurrently, so you don't need any locking.
So I was right above comment :-).
If you have some external code which is running on another thread and can touch the same objects (perhaps prior to calling async_write or async_wait), then those either need protection or you need to dispatch/post their work to the I/O thread instead (so that they cannot run concurrently with a callback).
No, my external code are boost libraries such as timers and io_service, if you have already said, timers won't create threads for me, then I won't need to worry about it. You comment here they cannot run concurrently with a callback is exactly I have tried design for many years, unless I misunderstood you again :-)
Bear in mind that if you're writing to that file synchronously, then it will also prevent the other callbacks from executing for however long that takes. Depending on what you're doing, that may or may not be a good thing.
Understood, it is an embedded MCU with a single processor, satiety and reliability are the priority in the initial design for using single thread, when I confident that all software functions are running well and mature, I might think to use multithreading. Thank you Gavin. Kind regards, - jupiter
On 2/09/2019 17:54, JH wrote:
Yes, three IO read / write, but only one thread. The thing I am not clear was your comment, "You may still need locks to protect things that are accessed from both callbacks".
That's not what I said. I said from both "callbacks" and "initiating functions". Or in more verbose form: accessed from both of: 1. callbacks 2. initiating functions The latter meaning something executed not on the callback thread -- named thus because in naive implementations usually the first read and most writes will be initiated externally like that.
On 9/2/19, Gavin Lambert via Boost
On 2/09/2019 17:54, JH wrote:
Yes, three IO read / write, but only one thread. The thing I am not clear was your comment, "You may still need locks to protect things that are accessed from both callbacks".
That's not what I said.
I said from both "callbacks" and "initiating functions".
Or in more verbose form: accessed from both of: 1. callbacks 2. initiating functions
The latter meaning something executed not on the callback thread -- named thus because in naive implementations usually the first read and most writes will be initiated externally like that.
Well, there is no other thread other than my callbacks to run ofstream, ifstream and Linux system read / write, I think the simple answer is I don't need lock in a single thread, if that is correct, I am truly relieved :-). Thanks Gavin.
participants (2)
-
Gavin Lambert
-
JH