当前位置:网站首页>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只是将自己的任务排入一个队列,当线程不忙时可以运行,忙时排队等待。
边栏推荐
- Theoretical description of linear equations and summary of methods for solving linear equations by eigen
- Torch learning notes (6) -- logistic regression model (self training)
- 统计图像中各像素值的数量
- Install apache+php+mysql+phpmyadmin xampp and its error resolution
- [LINUX]CentOS 7 安装MYSQL时报错“No package mysql-server available“No package zabbix-server-mysql availabl
- [linux]centos 7 reports an error when installing MySQL "no package MySQL server available" no package ZABBIX server MySQL available
- 解决Zabbix用snmp监控网络流量不准的问题
- PHP MySQL where clause
- NFT新的契机,多媒体NFT聚合平台OKALEIDO即将上线
- [combinatorics] generating function (positive integer splitting | unordered | ordered | allowed repetition | not allowed repetition | unordered not repeated splitting | unordered repeated splitting)
猜你喜欢

Naoqi robot summary 27

2022-2028 global lithium battery copper foil industry research and trend analysis report

What London Silver Trading software supports multiple languages

PHP MySQL inserts data

What problems can cross-border e-commerce sellers solve with multi platform ERP management system

Valentine's day, send you a little red flower~

2022-2028 global copper foil (thickness 12 μ M) industry research and trend analysis report

2022-2028 global aircraft head up display (HUD) industry research and trend analysis report

CTO and programmer were both sentenced for losing control of the crawler
![Bloom filter [proposed by bloom in 1970; redis cache penetration solution]](/img/f9/27a75454b464d59b9b3465d25fe070.jpg)
Bloom filter [proposed by bloom in 1970; redis cache penetration solution]
随机推荐
Bidding procurement scheme management of Oracle project management system
Niuke monthly race 31 minus integer
PHP MySQL inserts data
How to analyze the rising and falling rules of London gold trend chart
圖像24比特深度轉8比特深度
Install apache+php+mysql+phpmyadmin xampp and its error resolution
Nodejs (01) - introductory tutorial
Introduction to PHP MySQL
Redis core technology and practice - learning notes (11): why not just string
2022-2028 global copper foil (thickness 12 μ M) industry research and trend analysis report
PHP MySQL preprocessing statement
4. Load balancing and dynamic static separation
Have you learned the correct expression posture of programmers on Valentine's day?
Redis core technology and practice - learning notes (VIII) sentinel cluster: sentinel hung up
Sensor debugging process
分布式的任务分发框架-Gearman
Computer graduation design PHP campus address book telephone number inquiry system
Data analysis is popular on the Internet, and the full version of "Introduction to data science" is free to download
Codeforces Round #803 (Div. 2) C. 3SUM Closure
Torch learning notes (2) -- 11 common operation modes of tensor