Discussion:
[asio-users] asio::io_service::service::shutdown_service
Marat Abrarov
2011-10-16 17:33:41 UTC
Permalink
Hi, Chris and all users of Asio.

I have a small question about
virtual void boost::asio::io_service::service::shutdown_service().

Boost.Asio documentation says:
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/io_service__service/shutdown_service.html

But it is not enough accurate.
Actually (all released versions of Boost.Asio) io_service::service::shutdown_service is called only once - at
io_service::~io_service(). So, in general, there are no any concurrent operations related to any instance of
io_service::service (owned by destructing instance of io_service) already at this time (at
io_service::service::shutdown_service). In well-built architecture it cannot be (it have to be not) more than one thread
using the destructing instance of io_service. So we can assert that at the point of execution of
io_service::service::shutdown_service() till the end of lifetime of io_service::service there are no any concurrent
access to that instance of io_service::service.

Summing up: if we have flag (bool) shutdown_ at io_service::service and this flag is changed only at
io_service::service::shutdown_service (shutdown_ = true), so any other member function of io_service::service can check
shutdown_ without any defense from concurrent access (and without usage of interlocked* operations).

I use it at my project asio samples (ma::handler_storage_service class):
http://asio-samples.svn.sourceforge.net/viewvc/asio-samples/trunk/include/ma/handler_storage_service.hpp?revision=513&vi
ew=markup

Could it be described in Asio documentation? Or it cannot be guaranteed?

Regards,
Marat Abrarov.
Boris Schaeling
2011-10-17 18:55:35 UTC
Permalink
On Sun, 16 Oct 2011 19:33:41 +0200, Marat Abrarov
<***@mail.ru> wrote:

Hi Marat,
Post by Marat Abrarov
Hi, Chris and all users of Asio.
I have a small question about
virtual void boost::asio::io_service::service::shutdown_service().
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/io_service__service/shutdown_service.html
But it is not enough accurate.
Actually (all released versions of Boost.Asio)
io_service::service::shutdown_service is called only once - at
io_service::~io_service(). So, in general, there are no any concurrent
operations related to any instance of
io_service::service (owned by destructing instance of io_service) already at this time (at
io_service::service::shutdown_service). In well-built architecture it
I don't see any reference to concurrency or multithreading on
<http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/io_service__service/shutdown_service.html>?
As you explained that wouldn't make sense either. What makes you think
shutdown_service() exists because of multithreading? As far as I
understand shutdown_service() is used because when this member function is
called all services still exist. As a service can depend on and use
another one, one would need to be very careful otherwise about the order
of destruction if one had to clean up in a destructor instead of
shutdown_service().

Boris
Post by Marat Abrarov
[...]
Marat Abrarov
2011-10-17 23:48:03 UTC
Permalink
Hi, Boris.
Post by Boris Schaeling
I don't see any reference to concurrency or multithreading on
<http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/io_service__service/shutdown_servi
ce.html>?
That is the reason of my try to clarify. To clarify potentiality of concurrent (multithreaded) access to the same
instance of io_service::service at shutdown_service() from the other member functions of io_service::service.
Post by Boris Schaeling
As you explained that wouldn't make sense either. What makes you think
shutdown_service() exists because of multithreading?
I don't think so. shutdown_service() exists because of
~~~~~~~~~
Destroy all user-defined handler objects owned by the service.
~~~~~~~~~
The mission of shutdown_service() is clear for me.
Unclear is the need of synchronization at shutdown_service(). Services shipped with Boost.Asio do it (!).

In addition to
Post by Boris Schaeling
Actually (all released versions of Boost.Asio) io_service::service::shutdown_service is called only
once - at
io_service::~io_service(). So, in general, there are no any concurrent operations related to any
instance of
io_service::service (owned by destructing instance of io_service) already at this time (at
io_service::service::shutdown_service). In well-built architecture it cannot be (it have to be not)
more than one thread
using the destructing instance of io_service. So we can assert that at the point of execution of
io_service::service::shutdown_service() till the end of lifetime of io_service::service there are no
any concurrent
access to that instance of io_service::service.
Summing up: if we have flag (bool) shutdown_ at io_service::service and this flag is changed only at
io_service::service::shutdown_service (shutdown_ = true), so any other member function of
io_service::service can check
shutdown_ without any defense from concurrent access (and without usage of interlocked* operations).
I need to say:

This is true except internal threads used by other services (at the same instance of io_service). Those threads
potentially can result in concurrent calls to other member functions of instance of io_service::service while the
execution of shutdown_service() is in progress.

Regards,
Marat Abrarov.
Boris Schaeling
2011-10-18 17:44:45 UTC
Permalink
On Tue, 18 Oct 2011 01:48:03 +0200, Marat Abrarov
Post by Marat Abrarov
Hi, Boris.
Post by Boris Schaeling
I don't see any reference to concurrency or multithreading on
<http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/io_service__service/shutdown_servi
ce.html>?
That is the reason of my try to clarify. To clarify potentiality of
concurrent (multithreaded) access to the same
instance of io_service::service at shutdown_service() from the other
member functions of io_service::service.
Oh, sorry, then I misunderstood. I thought you were quoting something from
this webpage which I couldn't find. :)
Post by Marat Abrarov
[...]Unclear is the need of synchronization at shutdown_service().
Services shipped with Boost.Asio do it (!).
Can you tell me which services these are? I quickly looked at
win_iocp_io_service::shutdown_service() and
resolver_service_base::shutdown_service() but don't see any
synchronization there?

Boris
Post by Marat Abrarov
[...]
Marat Abrarov
2011-10-18 19:31:35 UTC
Permalink
Post by Boris Schaeling
Can you tell me which services these are? I quickly looked at
win_iocp_io_service::shutdown_service() and
resolver_service_base::shutdown_service() but don't see any
synchronization there?
Boost C++ Libraries 1.47

win_iocp_socket_service_base (detail/impl/win_iocp_socket_service_base.ipp:44)
win_iocp_handle_service (detail/impl/win_iocp_handle_service.ipp:79)
strand_service (detail/impl/strand_service.ipp:56) - probably it's ok because of
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/io_service__strand.html : Shared objects: Safe.
Post by Boris Schaeling
Post by Marat Abrarov
Summing up: if we have flag (bool) shutdown_ at io_service::service and this flag is changed only at
io_service::service::shutdown_service (shutdown_ = true), so any other member function of
io_service::service can check
shutdown_ without any defense from concurrent access (and without usage of interlocked* operations).
This is true except internal threads used by other services (at the same instance of io_service). Those threads
potentially can result in concurrent calls to other member functions of instance of io_service::service while the
execution of shutdown_service() is in progress.
But because of http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/threads.html (Internal Threads)
it can happen only if one io_service::service explicitly uses another io_service::service from its internal threads.
Such behavior may be simply forbidden (by documentation of related io_service::service) for particular
io_service::service to prevent concurrent access to the same instance of service during io_service::~io_service
execution.

In mine ma::handler_storage class I need to guarantee that the state of particular instance of ma::handler_storage will
not be changed concurrently (for the use of ma::handler_storage::target()).

Regards,
Marat Abrarov.
Boris Schaeling
2011-10-18 20:18:05 UTC
Permalink
On Tue, 18 Oct 2011 21:31:35 +0200, Marat Abrarov
Post by Marat Abrarov
Post by Boris Schaeling
Can you tell me which services these are? I quickly looked at
win_iocp_io_service::shutdown_service() and
resolver_service_base::shutdown_service() but don't see any
synchronization there?
Boost C++ Libraries 1.47
win_iocp_socket_service_base
(detail/impl/win_iocp_socket_service_base.ipp:44)
win_iocp_handle_service (detail/impl/win_iocp_handle_service.ipp:79)
Hm, I don't see an obvious reason either why the mutex should be required.
Maybe Chris used the mutex simply everywhere where he accessed impl_list_
(defensive programming)?
Post by Marat Abrarov
[...]But because of
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/threads.html
(Internal Threads)
it can happen only if one io_service::service explicitly uses another
io_service::service from its internal threads.
Such behavior may be simply forbidden (by documentation of related
io_service::service) for particular
io_service::service to prevent concurrent access to the same instance of
service during io_service::~io_service
execution.
Nice idea! But then I would prefer the mutex instead of having to debug
something like this one day. ;)

Boris
Post by Marat Abrarov
[...]
Marat Abrarov
2011-10-18 21:27:50 UTC
Permalink
Post by Boris Schaeling
Post by Marat Abrarov
Boost C++ Libraries 1.47
win_iocp_socket_service_base
(detail/impl/win_iocp_socket_service_base.ipp:44)
win_iocp_handle_service (detail/impl/win_iocp_handle_service.ipp:79)
Hm, I don't see an obvious reason either why the mutex should be required.
Maybe Chris used the mutex simply everywhere where he accessed impl_list_
(defensive programming)?
Of course, it's also defensive programming.
Post by Boris Schaeling
Post by Marat Abrarov
[...]But because of
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/threads.html
(Internal Threads)
it can happen only if one io_service::service explicitly uses another
io_service::service from its internal threads.
Such behavior may be simply forbidden (by documentation of related
io_service::service) for particular
io_service::service to prevent concurrent access to the same instance of
service during io_service::~io_service
execution.
Nice idea! But then I would prefer the mutex instead of having to debug
something like this one day. ;)
I can't use mutex there. If I use mutex then that mutex have to be shared across all (!)
instances of ma::handler_storage (as member of ma::handler_storage_service) and
across all member functions of ma::handler_storage.
It's too expensive because of the paradigm of ma::handler_storage (Shared objects: Unsafe).
Access to most of member functions of ma::handler_storage have to be as lightweight as possible.
Usage of service-wide mutex at any member function (except constructor/destructor) will negate
the whole idea of ma::handler_storage class.

Regards,
Marat Abrarov.
Boris Schaeling
2011-10-18 21:41:17 UTC
Permalink
On Tue, 18 Oct 2011 23:27:50 +0200, Marat Abrarov
[...]I can't use mutex there. If I use mutex then that mutex have to be
shared across all (!)
instances of ma::handler_storage (as member of
ma::handler_storage_service) and
across all member functions of ma::handler_storage.
It's too expensive because of the paradigm of ma::handler_storage (Shared objects: Unsafe).
Access to most of member functions of ma::handler_storage have to be as
lightweight as possible.
Usage of service-wide mutex at any member function (except
constructor/destructor) will negate
the whole idea of ma::handler_storage class.
I'm not sure if anyone here can help you now - at least I don't know
anything about ma::handler_storage. If you think it's better not to use a
mutex in shutdown_service() in your service, you don't need to use it? But
maybe I don't understand the problem again. :)

Boris

Loading...