Amir Taaki
2012-06-16 04:58:12 UTC
Hi,
Typically in asio we post member callbacks of objects using shared_from_this() to ensure that the object doesn't become destroyed before the posted handler executes:
strand_.post(std::bind(&myobject::foo, shared_from_this(), 110, xyz));
Christopher Kohlhoff's boostcon talk on boost::asio, he discussed two common patterns used in asio. One of those was "the buck stops here". In This pattern might be used for the interface of a class which posts the work to another thread, serialising access to internal shared data through a strand.
class something
: public std::enable_shared_from_this<something>
{
public:
void foo(int x)
{
strand_.post(std::bind(&something::do_foo, x));
}
private:
void do_foo(int x)
{
// do something non-threadsafe shared_state_ member
}
io_service::strand strand_;
data shared_state_;
};
Now if you have 2 object posting between each other's strands, then you get a problem when an io_service for one strand goes out of scope but not for the other (a strand pointing to a destructed io_service). So then you keep the io_service alive with the strand.
class async_strand
{
// ...
private:
typedef std::shared_ptr<io_service> io_service_ptr;
io_service_ptr service_;
io_service::strand strand_;
};
But now we have created a circular reference whereby something is posting itself to an object that it owns. The destructor of the class 'something' will not get called.
What are the typical ways of designing programs that own strands? All the examples I've seen are very simple with a single io_service that always outlives the strand encapsulating the class members. But that model doesn't hold with multiple strands from different io_service's that are posting to each other.
Typically in asio we post member callbacks of objects using shared_from_this() to ensure that the object doesn't become destroyed before the posted handler executes:
strand_.post(std::bind(&myobject::foo, shared_from_this(), 110, xyz));
Christopher Kohlhoff's boostcon talk on boost::asio, he discussed two common patterns used in asio. One of those was "the buck stops here". In This pattern might be used for the interface of a class which posts the work to another thread, serialising access to internal shared data through a strand.
class something
: public std::enable_shared_from_this<something>
{
public:
void foo(int x)
{
strand_.post(std::bind(&something::do_foo, x));
}
private:
void do_foo(int x)
{
// do something non-threadsafe shared_state_ member
}
io_service::strand strand_;
data shared_state_;
};
Now if you have 2 object posting between each other's strands, then you get a problem when an io_service for one strand goes out of scope but not for the other (a strand pointing to a destructed io_service). So then you keep the io_service alive with the strand.
class async_strand
{
// ...
private:
typedef std::shared_ptr<io_service> io_service_ptr;
io_service_ptr service_;
io_service::strand strand_;
};
But now we have created a circular reference whereby something is posting itself to an object that it owns. The destructor of the class 'something' will not get called.
What are the typical ways of designing programs that own strands? All the examples I've seen are very simple with a single io_service that always outlives the strand encapsulating the class members. But that model doesn't hold with multiple strands from different io_service's that are posting to each other.