Reputation: 567
Said I have a worker class
class MyWorker : public std::enable_shared_from_this<MyWorker> {
public:
MyWorker(boost::asio::io_service& ioService) : strand_(ioService) {}
void Work(int n) {
strand_.post([weak_this = weak_from_this(), n]() {
printf("work %d run from strand\n", n);
if (auto ptr = weak_this.lock()) ptr->DoWork(n);
});
}
void DoWork(int n) {
n_ = n;
printf("work %d done\n", n);
}
private:
boost::asio::io_service::strand strand_;
int n_;
};
Anyone can post works to a worker object, and it will be en-queued and do work in sequence. When I want to stop a worker object, I can just un-reference shared _ptr. Pending work will not call into object (protected by weak_ptr)
Here is example scenario
int main() {
boost::asio::io_service ioService;
auto worker = std::make_shared<MyWorker>(ioService);
ioService.post([] () { printf("other work 1\n"); });
worker->Work(1);
ioService.post([] () { printf("other work 2\n"); });
worker->Work(2);
worker.reset(); // <- strand_ destroyed after this line
ioService.run();
return 0;
}
This exmaple can run without crash. The output is
other work 1
work 1 run from strand
other work 2
work 2 run from strand
No "work 1 done", "work 2 done" which is expected.
But at the time I called io_service::run(), strand is already destroyed. Is this safe? Or something undefined behavior may happened?
Upvotes: 3
Views: 514
Reputation: 392833
Oh, I almost forgot about this question since my comment:
Looks fine to me (much easier to see if you imagine MyWorker::Work as a free function). It does assume that it's okay to have wrapped handlers even after the strand object is destroyed. I think that is okay, but I'd need to check.
I did have a look at the implementation and indeed the implementation of the strand service is such that it is safe to have handlers associated with them after destructing the strand
instance.
That makes your code fine.
Upvotes: 1