当前位置:网站首页>Boost.Asio Library
Boost.Asio Library
2022-07-03 18:25:00 【是浩浩子】
1. io_service
io_service
是Boost::Asio命名空间内的核心对象,I/O service是一个用于访问操作系统资源的通道,并在提交I/O请求的程序和执行I/O请求的操作系统之间建立通信。io_service对象使用最频繁的方法是run()
,它用于不断应对io_service对象需要处理的事件。因此它会阻塞,直到所有的事件处理完毕。
如果想让io_service
对象在没有事件需要处理时,run()
依然阻塞,可以使用work()
方法。例如:
#include <boost/asio.hpp>
#include <iostream>
int main(void) {
boost::asio::io_service io_svc;
boost::asio::io_service::work worker(io_svc); // 相当于改变了io_svc的性质
io_svc.run(); // 这个等待并不占用CPU资源
std::cout << "We will not see this line in console window :(" << std::endl;
return 0;
}
在上面的代码中,work
类通知io_service
对象它有工作要做,但我们没有定义工作是什么。因此,程序将被无限阻塞,所以最后一行代码不会输出。阻塞的原因是run()函数被调用了。
与run()
相对的是poll()
方法。poll()
方法用于处理就绪的程序,直到没有剩余的就绪的程序或直到io_service对象停止。但是,与run()函数相比,poll()函数不会阻塞程序,即使使用了work()
方法。
2. 删除work对象
可以通过从io_service
对象中移除工作对象来解除程序阻塞,但是为了移除工作对象本身,我们必须使用指向工作对象的指针。
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include<boost/chrono.hpp>
#include <iostream>
int main(void) {
boost::asio::io_service io_svc;
boost::shared_ptr<boost::asio::io_service::work> worker(
new boost::asio::io_service::work(io_svc));
worker.reset(); // 销毁指针,所有待处理的工作都将结束
io_svc.run();
std::cout << "We will not see this line in console window :(" << std::endl;
return 0;
}
3. 处理多线程
一个io_service
在多个线程中处理。
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <iostream>
boost::asio::io_service io_svc;
int a = 0;
void WorkerThread() {
std::cout << ++a << ".\n";
io_svc.run();
std::cout << "End.\n";
}
int main(void) {
boost::shared_ptr<boost::asio::io_service::work> worker(
new boost::asio::io_service::work(io_svc));
std::cout << "Press ENTER key to exit!" << std::endl;
boost::thread_group threads;
for(int i=0; i<5; i++)
threads.create_thread(WorkerThread);
std::cin.get();
io_svc.stop(); // worker.reset();
threads.join_all();
return 0;
}
4. 拷贝io_service指针
其他需要注意的是io_service
是不可拷贝的对象。但可以通过在shared_ptr指针中实例化io_service对象,使其可复制,这样我们就可以将它绑定到worker thread()
方法中,作为线程处理函数使用。
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost::asio;
void workThread(std::shared_ptr<io_service> iosvc, int counter) {
std::cout << counter << std::endl;
iosvc->run();
std::cout << "End." << std::endl;
}
int main() {
//io_service ios;
auto io_svc = std::make_shared<io_service>();
std::shared_ptr<io_service::work> worker(new io_service::work(*io_svc));
std::cout << "Press ENTER key to exit!" << std::endl;
boost::thread_group threads;
for(int i=1; i<=5; i++) {
threads.create_thread(boost::bind(&workThread, io_svc, i));
}
std::cin.get();
worker.reset(); // io_svc->stop(); 是将所有的工作停止,即使没有做完。worker.reset();像是取消io_service对象的work属性
threads.join_all();
return 0;
}
5. 互斥锁
在上述几个多线程的例子中,运行是随机的。因为std::cout对象是一个全局对象,一次从不同的线程写入,可能会导致输出格式化问题。可以使用互斥锁来同步对任何全局数据或共享数据的访问。
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr<boost::asio::io_service> iosvc,
int counter) {
global_stream_lock.lock();
std::cout << counter << ".\n";
global_stream_lock.unlock();
iosvc->run();
global_stream_lock.lock();
std::cout << "End.\n";
global_stream_lock.unlock();
}
int main(void) {
boost::shared_ptr<boost::asio::io_service> io_svc(
new boost::asio::io_service
);
boost::shared_ptr<boost::asio::io_service::work> worker(
new boost::asio::io_service::work(*io_svc)
);
std::cout << "Press ENTER key to exit!" << std::endl;
boost::thread_group threads;
for(int i=1; i<=5; i++)
threads.create_thread(boost::bind(&WorkerThread, io_svc, i));
std::cin.get();
io_svc->stop();
threads.join_all();
return 0;
}
6. 向 I/O service分发工作
在io_service
中有两个方法可以给io_service
分配任务:post()
方法用于请求io_service
对象在我们将所有工作排队后运行io_service
对象对应的work,所以它不允许我们立即运行工作。而dispatch()
方法也用于向io_service
对象发出一个请求来运行io_service
对象的工作,但它会立即执行工作,而不会排队。
post()
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex global_stream_lock;
void WorkerThread(boost::shared_ptr<boost::asio::io_service> iosvc,
int counter) {
global_stream_lock.lock();
std::cout << counter << ".\n";
global_stream_lock.unlock();
iosvc->run();
global_stream_lock.lock();
std::cout << "End.\n";
global_stream_lock.unlock();
}
size_t fac(size_t n) {
if ( n <= 1 ) {
return n;
}
boost::this_thread::sleep(
boost::posix_time::milliseconds(1000)
);
return n * fac(n - 1);
}
void CalculateFactorial(size_t n) {
global_stream_lock.lock();
std::cout << "Calculating " << n << "! factorial" << std::endl;
global_stream_lock.unlock();
size_t f = fac(n);
global_stream_lock.lock();
std::cout << n << "! = " << f << std::endl;
global_stream_lock.unlock();
}
int main(void) {
boost::shared_ptr<boost::asio::io_service> io_svc(
new boost::asio::io_service
);
boost::shared_ptr<boost::asio::io_service::work> worker(
new boost::asio::io_service::work(*io_svc)
);
global_stream_lock.lock();
std::cout << "The program will exit once all work has finished." << std::endl;
global_stream_lock.unlock();
boost::thread_group threads;
for(int i=1; i<=5; i++)
threads.create_thread(boost::bind(&WorkerThread, io_svc, i));
io_svc->post(boost::bind(CalculateFactorial, 5));
io_svc->post(boost::bind(CalculateFactorial, 6));
io_svc->post(boost::bind(CalculateFactorial, 7));
worker.reset();
threads.join_all();
return 0;
}
在main函数中,使用post()函数将三个函数对象发布到io_service对象上。我们在初始化5个工作线程时将io_service对象指针分配到5个线程中。这样,因为我们在每个线程中调用io_service对象的run()函数,所以io_service对象的work将会运行post()方法发布的工作。
dispatch()
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost::asio;
//boost::mutex global_lock;
void Dispatch(int i) {
std::cout << "dispatch() function for i=" << i << std::endl;
}
void Post(int i) {
std::cout << "post() function for i=" << i << std::endl;
}
void workerThread(std::shared_ptr<io_service> iosv) {
std::cout << "Thread Start." <<std::endl;
iosv->run();
std::cout << "Thread Finish." << std::endl;
}
void running(std::shared_ptr<io_service> iosv) {
for(int i=0; i<5; i++) {
iosv->dispatch(boost::bind(&Dispatch, i));
iosv->post(boost::bind(&Post, i));
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
}
int main() {
auto iosv =std::make_shared<io_service>();
//io_service::work worker(*iosv);
auto worker = std::make_shared<io_service::work>(*iosv); // make_shared<io_service::work>会调用work的构造函数
boost::thread_group threads;
threads.create_thread(boost::bind(&workerThread, iosv));
iosv->post(boost::bind(&running, iosv));
worker.reset();
threads.join_all();
return 0;
}
输出结果:
Thread Start.
dispatch() function for i=0
dispatch() function for i=1
dispatch() function for i=2
dispatch() function for i=3
dispatch() function for i=4
post() function for i=0
post() function for i=1
post() function for i=2
post() function for i=3
post() function for i=4
Thread Finish.
按照常规的理解输出的结果应该是dispatch()和post()交替执行,但是结果却是先执行dispatch()再执行post()。这是因为dispatch()分发的工作要求从当前工作线程立即调用,而post()必须等到工作线程的处理程序完成后才能被调用。换句话说,post()在工作线程有其他未决的事件时需要排队等待,等到处理程序完成执行后才能被允许执行。
就是说我们首先post了一个running工作,而在这个工作中,又dispatch和post了工作,那么workerThread所在的线程中首先处理running工作,当运行到dispatch时,虽然running工作没有完成,但是dispatch也要求立即运行,而post只是将自己的任务排入一个队列,当线程不忙时可以运行,忙时排队等待。
边栏推荐
- Change the single node of Postgres database into master-slave
- [linux]centos 7 reports an error when installing MySQL "no package MySQL server available" no package ZABBIX server MySQL available
- Bloom filter [proposed by bloom in 1970; redis cache penetration solution]
- What kind of experience is it when the Institute earns 20000 yuan a month?
- OpenSSL的SSL/BIO_get_fd
- [combinatorics] generating function (generating function application scenario | using generating function to solve recursive equation)
- After the festival, a large number of people change careers. Is it still time to be 30? Listen to the experience of the past people
- Lesson 13 of the Blue Bridge Cup -- tree array and line segment tree [exercise]
- English语法_形容词/副词3级 - 倍数表达
- Raft 日志复制
猜你喜欢
AcWing 271. Teacher Yang's photographic arrangement [multidimensional DP]
Torch learning notes (3) -- univariate linear regression model (self training)
Computer graduation project PHP library book borrowing management system
PHP MySQL inserts multiple pieces of data
PHP MySQL preprocessing statement
Codeforces Round #803 (Div. 2) C. 3SUM Closure
2022-2028 global aircraft head up display (HUD) industry research and trend analysis report
PHP MySQL create database
Naoqi robot summary 27
What problems can cross-border e-commerce sellers solve with multi platform ERP management system
随机推荐
4. Load balancing and dynamic static separation
What problems can cross-border e-commerce sellers solve with multi platform ERP management system
Torch learning notes (6) -- logistic regression model (self training)
Redis core technology and practice - learning notes (VIII) sentinel cluster: sentinel hung up
Postfix 技巧和故障排除命令
[linux]centos 7 reports an error when installing MySQL "no package MySQL server available" no package ZABBIX server MySQL available
[combinatorics] exponential generating function (concept of exponential generating function | permutation number exponential generating function = combinatorial number ordinary generating function | e
Summary and Reflection on the third week of winter vacation
A. Berland Poker &1000【简单数学思维】
win32:堆破壞的dump文件分析
PHP MySQL order by keyword
Keepalived 设置不抢占资源
English语法_名词 - 分类
PHP MySQL where clause
How to expand the capacity of golang slice slice
The second largest gay dating website in the world was exposed, and the status of programmers in 2022
Naoqi robot summary 27
ES7 - Optimization of promise
Coordinate layer conversion tool (video)
English语法_形容词/副词3级 - 倍数表达