Passing io_service to socket in implementation file after initialization in header file

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
If I initialize an io_service object and a socket object in my header file, how do I pass io_service to the socket as a parameter in my implementation file?

Take this header file as an example:

// foo.h

#include <boost/asio.hpp>

class foo
{
public:

    foo(); // Constructor.

private:

    boost::asio::io_service ios;

    boost::asio::ip::udp::socket sock;
};

And the corresponding implementation file:

// foo.cc

#include "foo.h"

foo::foo()
{
    sock(ios); // <-- This throws a compiler error.
}

Why doing sock(ios); doesn't work?
What is the proper way to do it?

Thank you.

Álvaro

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
Move your initialization of sock into the initialization list. Eg: foo::foo() : sock{ios} {}. Without this, the socket is default constructed without any io service and then you tried to invoke the call operator, not the constructor.

On Mon, Jun 18, 2018, 09:13 Álvaro Cebrián Juan via Boost-users <[hidden email]> wrote:
If I initialize an io_service object and a socket object in my header file, how do I pass io_service to the socket as a parameter in my implementation file?

Take this header file as an example:

// foo.h

#include <boost/asio.hpp>

class foo
{
public:

    foo(); // Constructor.

private:

    boost::asio::io_service ios;

    boost::asio::ip::udp::socket sock;
};

And the corresponding implementation file:

// foo.cc

#include "foo.h"

foo::foo()
{
    sock(ios); // <-- This throws a compiler error.
}

Why doing sock(ios); doesn't work?
What is the proper way to do it?

Thank you.

Álvaro
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
In reply to this post by Boost - Users mailing list
On Mon, Jun 18, 2018 at 6:13 AM Álvaro Cebrián Juan via Boost-users
<[hidden email]> wrote:
> Why doing sock(ios); doesn't work?

What is the complete error message from the compiler?

Thanks
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
A note of caution.

In all but the most exceptional of cases, you will want one io_service per application. 

Rather than tie the entire application to one instance of a class, which might make testing difficult, you may want to consider providing the io_service to the Foo as a dependency injection, with its lifetime controlled by main().

Example (including the fixed constructor):

#include <boost/asio.hpp>

class foo
{
public:

    foo(boost::asio::io_service& ios); // Constructor.

private:

    boost::asio::io_service& ios;

    boost::asio::ip::udp::socket sock;
};

foo::foo(boost::asio::io_service& ios)
: ios(ios)
, sock(ios)
{
}


int main()
{
    boost::asio::io_service myios;
    
    foo f1(myios);  // note - io_service is injected
    foo f2(myios);
    
    //... generate events etc
    
    myios.run();
    
    // now destroy foos and lastly, myios
}


On Mon, 18 Jun 2018 at 15:46, Vinnie Falco via Boost-users <[hidden email]> wrote:
On Mon, Jun 18, 2018 at 6:13 AM Álvaro Cebrián Juan via Boost-users
<[hidden email]> wrote:
> Why doing sock(ios); doesn't work?

What is the complete error message from the compiler?

Thanks
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
You want one io_service per endpoint, not per application.

On Monday, June 18, 2018, Richard Hodges via Boost-users <[hidden email]> wrote:
A note of caution.

In all but the most exceptional of cases, you will want one io_service per application. 

Rather than tie the entire application to one instance of a class, which might make testing difficult, you may want to consider providing the io_service to the Foo as a dependency injection, with its lifetime controlled by main().

Example (including the fixed constructor):

#include <boost/asio.hpp>

class foo
{
public:

    foo(boost::asio::io_service& ios); // Constructor.

private:

    boost::asio::io_service& ios;

    boost::asio::ip::udp::socket sock;
};

foo::foo(boost::asio::io_service& ios)
: ios(ios)
, sock(ios)
{
}


int main()
{
    boost::asio::io_service myios;
    
    foo f1(myios);  // note - io_service is injected
    foo f2(myios);
    
    //... generate events etc
    
    myios.run();
    
    // now destroy foos and lastly, myios
}


On Mon, 18 Jun 2018 at 15:46, Vinnie Falco via Boost-users <[hidden email]> wrote:
On Mon, Jun 18, 2018 at 6:13 AM Álvaro Cebrián Juan via Boost-users
<[hidden email]> wrote:
> Why doing sock(ios); doesn't work?

What is the complete error message from the compiler?

Thanks
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list


On Mon, Jun 18, 2018, 14:53 james via Boost-users <[hidden email]> wrote:
You want one io_service per endpoint, not per application.
I think you're confusing io_service with strands. One io_service/context should be able to handle multiple endpoints and even multiple threads running the same io service.

On Monday, June 18, 2018, Richard Hodges via Boost-users <[hidden email]> wrote:
A note of caution.

In all but the most exceptional of cases, you will want one io_service per application. 

Rather than tie the entire application to one instance of a class, which might make testing difficult, you may want to consider providing the io_service to the Foo as a dependency injection, with its lifetime controlled by main().

Example (including the fixed constructor):

#include <boost/asio.hpp>

class foo
{
public:

    foo(boost::asio::io_service& ios); // Constructor.

private:

    boost::asio::io_service& ios;

    boost::asio::ip::udp::socket sock;
};

foo::foo(boost::asio::io_service& ios)
: ios(ios)
, sock(ios)
{
}


int main()
{
    boost::asio::io_service myios;
    
    foo f1(myios);  // note - io_service is injected
    foo f2(myios);
    
    //... generate events etc
    
    myios.run();
    
    // now destroy foos and lastly, myios
}


On Mon, 18 Jun 2018 at 15:46, Vinnie Falco via Boost-users <[hidden email]> wrote:
On Mon, Jun 18, 2018 at 6:13 AM Álvaro Cebrián Juan via Boost-users
<[hidden email]> wrote:
> Why doing sock(ios); doesn't work?

What is the complete error message from the compiler?

Thanks
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
In reply to this post by Boost - Users mailing list
On Mon, Jun 18, 2018 at 11:54 AM james via Boost-users
<[hidden email]> wrote:
> You want one io_service per endpoint, not per application.

What? No... You're saying a separate io_context for each socket?
That's not necessary. These are the common models:

* One io_context, one thread:
   - Implicit strand (no locks needed)

* One io_context, multiple threads
   - Explicit strand needed
   - Different sockets can process data concurrently

* One io_context for each thread
   - Implicit strand (no locks needed)
   - Sockets in different contexts can process data concurrently
   - Passing data between sockets in different contexts requires care
(e.g. broadcasts)

I know of no benefit to one io_context per socket, nor have I seen an
implementation which uses that model.

Thanks
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
No, not per socket. One per port that accepts connections if you're a server, and one per host you're connecting to if you're a client.

On Monday, June 18, 2018, Vinnie Falco via Boost-users <[hidden email]> wrote:
On Mon, Jun 18, 2018 at 11:54 AM james via Boost-users
<[hidden email]> wrote:
> You want one io_service per endpoint, not per application.

What? No... You're saying a separate io_context for each socket?
That's not necessary. These are the common models:

* One io_context, one thread:
   - Implicit strand (no locks needed)

* One io_context, multiple threads
   - Explicit strand needed
   - Different sockets can process data concurrently

* One io_context for each thread
   - Implicit strand (no locks needed)
   - Sockets in different contexts can process data concurrently
   - Passing data between sockets in different contexts requires care
(e.g. broadcasts)

I know of no benefit to one io_context per socket, nor have I seen an
implementation which uses that model.

Thanks
_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
On 19/06/2018 07:34, james wrote:
> No, not per socket. One per port that accepts connections if you're a
> server, and one per host you're connecting to if you're a client.

While you *can* do that, it's unusual and doesn't really provide any
particular benefit over the models that Vinnie specified.

Essentially, if you make one thread per endpoint then you have the same
thing as the "one io_context per thread" model that Vinnie spoke of.

If you have multiple independent threadpools per endpoint then you have
the combination of the "one io_context per thread" and "one io_context,
multiple threads" models (which works, but is still unusual as you start
to run into more drawbacks than benefits with this pattern; so I
wouldn't recommend it).

Otherwise, you have multiple io_contexts per thread, which is a Bad Idea™.

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
We found a dedicated thread per io_service made things a lot easier. Couple that with your favourite flavour
of concurrent queue to keep io async callback code short.
Strands seem perfect if you want to kill any scalability so we never even considered patterns that required them.


On Tuesday, June 19, 2018, Gavin Lambert via Boost-users <[hidden email]> wrote:
On 19/06/2018 07:34, james wrote:
No, not per socket. One per port that accepts connections if you're a server, and one per host you're connecting to if you're a client.

While you *can* do that, it's unusual and doesn't really provide any particular benefit over the models that Vinnie specified.

Essentially, if you make one thread per endpoint then you have the same thing as the "one io_context per thread" model that Vinnie spoke of.

If you have multiple independent threadpools per endpoint then you have the combination of the "one io_context per thread" and "one io_context, multiple threads" models (which works, but is still unusual as you start to run into more drawbacks than benefits with this pattern; so I wouldn't recommend it).

Otherwise, you have multiple io_contexts per thread, which is a Bad Idea™.

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: Passing io_service to socket in implementation file after initialization in header file

Boost - Users mailing list
On 19/06/2018 19:21, james wrote:
> We found a dedicated thread per io_service made things a lot easier.

Of course; that's the "one io_context, one thread" model.  It's always
the easiest to code, but has other tradeoffs.

> Strands seem perfect if you want to kill any scalability so we never
> even considered patterns that required them.

Having separate dedicated threads per X is fine as long as X is
relatively small (less than #cpus).  It does not scale well.

When X surpasses the #cpus, a stranded threadpool usually provides
superior performance.

If your X is hardcoded then perhaps it's not a big concern, but if it's
configurable by the end user, it might be...

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users