栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Boost.Asio Library

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Boost.Asio Library

1. io_service

io_service是Boost::Asio命名空间内的核心对象,I/O service是一个用于访问操作系统资源的通道,并在提交I/O请求的程序和执行I/O请求的操作系统之间建立通信。io_service对象使用最频繁的方法是run(),它用于不断应对io_service对象需要处理的事件。因此它会阻塞,直到所有的事件处理完毕。
如果想让io_service对象在没有事件需要处理时,run()依然阻塞,可以使用work()方法。例如:

#include 
#include 
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 
#include 
#include
#include 

int main(void) {
	boost::asio::io_service io_svc;
	boost::shared_ptr 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 
#include 
#include 
#include 

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 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 
#include 
#include 
#include 

using namespace boost::asio;

void workThread(std::shared_ptr 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();
    std::shared_ptr 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 
#include 
#include 
#include 
#include 

boost::mutex global_stream_lock;

void WorkerThread(boost::shared_ptr 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 io_svc(
								new boost::asio::io_service
);
	boost::shared_ptr 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 
#include 
#include 
#include 
#include 

boost::mutex global_stream_lock;

void WorkerThread(boost::shared_ptr 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 io_svc(
								new boost::asio::io_service
 );
	boost::shared_ptr 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 
#include 
#include 
#include 

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 iosv) {
    std::cout << "Thread Start." <run();

    std::cout << "Thread Finish." << std::endl;
}

void running(std::shared_ptr 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::work worker(*iosv);
    auto worker = std::make_shared(*iosv); // make_shared会调用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只是将自己的任务排入一个队列,当线程不忙时可以运行,忙时排队等待。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1001010.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号