0%

boost asio example

Code Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

/*
https://mmoaay.gitbooks.io/boost-asio-cpp-network-programming-chinese/content/Chapter3.html
https://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/tutorial/tuttimer2/src.html
sync: blocking ,return until job done
async: non-blocking, return immediately
*/

// Timer.1. - Using a timer synchronously
int snyc_timer()
{
boost::asio::io_service io;

boost::asio::deadline_timer t(io, boost::posix_time::seconds(2));
t.wait(); // blocking wait on the timer

std::cout << "Hello, world!" << std::endl;

return 0;
}

// Timer.2 - Using a timer asynchronously
void print2(const boost::system::error_code& /*e*/)
{
std::cout << "thread #" << boost::this_thread::get_id() << std::endl;
std::cout << "Hello, world!" << std::endl;
}

int asnyc_timer()
{
boost::asio::io_service io;

boost::asio::deadline_timer t(io, boost::posix_time::seconds(2));
t.async_wait(&print2); // asnyc,non-blocking,return immediately
/*
The asio library provides a guarantee that callback handlers will only be called from threads that are currently calling io_service::run().
asio库会确保handler会在io_service::run()所在的thread中运行。
*/

std::cout << "[main thread] #" << boost::this_thread::get_id() << std::endl;
std::cout << "here" << std::endl;

io.run();// sync: blocking ,return until job done

return 0;
}

// Timer.3 - Binding arguments to a handler
void print(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* t, int* count)
{
if (*count < 5)
{
std::cout << *count << std::endl;
++(*count);

t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
t->async_wait(boost::bind(print,
boost::asio::placeholders::error, t, count));
}
}

int asnyc_timer_with_params()
{
boost::asio::io_service io;

int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count));

io.run();

std::cout << "Final count is " << count << std::endl;

return 0;
}

// Timer.4 - Using a member function as a handler
class printer
{
public:
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer_.async_wait(boost::bind(&printer::print, this));
}

~printer()
{
std::cout << "Final count is " << count_ << std::endl;
}

void print()
{
if (count_ < 5)
{
std::cout << count_ << std::endl;
++count_;

timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this));
}
else {
std::cout << "print do nothing..." << std::endl;
}
}

private:
boost::asio::deadline_timer timer_;
int count_;
};

int asnyc_timer_with_class_method()
{
boost::asio::io_service io;
printer p(io);
io.run();

return 0;
}

// Timer.5 - Synchronising handlers in multithreaded programs

/*
The previous four tutorials avoided the issue of handler synchronisation
by calling the io_service::run() function from one thread only. As you
already know, the asio library provides a guarantee that callback handlers
will only be called from threads that are currently calling io_service::run().

Consequently, calling io_service::run() from only one thread ensures that
callback handlers cannot run concurrently.

By wrapping the handlers using the same boost::asio::strand, we are ensuring
that they cannot execute concurrently.

在一个thread中调用io_service::run(),能够确保其对应的回调handlers不会并行执行。
但是在A和B两个thread中调用io_service::run(),A对应的handler和B对应的handler会并行执行。
【handler不是线程安全的】

如何解决多线程调用io_service::run() 其对应的handler会并行执行的问题?
使用boost::asio::io_service::strand对象。

An boost::asio::strand guarantees that, for those handlers that are dispatched
through it, an executing handler will be allowed to complete before the next one
is started.

By wrapping the handlers using the same boost::asio::strand, we are ensuring that
they cannot execute concurrently.

同一个srand对象,能够确保其wrap的handler能够顺序执行。
即print1和print2在2个线程中不会并行执行。
*/
class printer_sync
{
public:
printer_sync(boost::asio::io_service& io)
: strand_(io),
timer1_(io, boost::posix_time::seconds(1)),
timer2_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer1_.async_wait(strand_.wrap(boost::bind(&printer_sync::print1, this)));
timer2_.async_wait(strand_.wrap(boost::bind(&printer_sync::print2, this)));
}

~printer_sync()
{
std::cout << "Final count is " << count_ << std::endl;
}

void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ <<",thread #" << boost::this_thread::get_id() << std::endl;
++count_;

timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
timer1_.async_wait(strand_.wrap(boost::bind(&printer_sync::print1, this)));
}
else {
std::cout << "Timer 1: else " << count_ << std::endl;
}
}

void print2()
{
if (count_ < 10)
{

std::cout << "Timer 2: " << count_ << ",thread #" << boost::this_thread::get_id() << std::endl;
++count_;

timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
timer2_.async_wait(strand_.wrap(boost::bind(&printer_sync::print2, this)));
}
else {
std::cout << "Timer 2: else " << count_ << std::endl;
}
}

private:
boost::asio::io_service::strand strand_; // wrap handlers
boost::asio::deadline_timer timer1_;
boost::asio::deadline_timer timer2_;
int count_;
};

int sync_handlers()
{
boost::asio::io_service io;
printer_sync p(io);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
std::cout << "[main thread] #" << boost::this_thread::get_id() << std::endl;

std::cout << "[1] begin to run" << std::endl;
io.run(); // blocking until job done
std::cout << "[2] after run" << std::endl;
t.join();
std::cout << "[3] after join" << std::endl;
return 0;
}

int main(int argc, char* argv[])
{
//snyc_timer();
//asnyc_timer();
//asnyc_timer_with_params();
//asnyc_timer_with_class_method();
sync_handlers();
return 0;
}

Reference

History

  • 20180523: created.