首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

12.4 只初始化一次共享资源

问题

有一序列的线程,如何使得它们能使用那些只能初始化一次的资源?

解决方案

在线程使用这个资源前就初始化这个资源,或者如果你不能这样做的话,就调用定义在<boost/thread/once.hpp>中的call_once函数。示例12-5说明该如何使用这个call_once函数。

示例12-5  只初始化一次某个资源

#include <iostream>

#include <boost/thread/thread.hpp>

#include <boost/thread/once.hpp>

// Some sort of connection class that should only be initialized once

struct Conn {

   static void init() {++i_;}

   static boost::once_flag init_;

   static int i_;

   // ...

};

int Conn::i_ = 0;

boost::once_flag Conn::init_ = BOOST_ONCE_INIT;

void worker() {

   boost::call_once(Conn::init, Conn::init_);

   // Do the real work...

}

Conn c;  // You probably don't want to use a global, so see the

         // next Recipe

int main() {

   boost::thread_group grp;

   for (int i = 0; i < 100; ++i)

 grp.create_thread(worker);

   grp.join_all();

   std::cout << c.i_ << '\n'; // c.i_ = 1

}

讨论

一个共享资源不得不再在某个地方被初始化,并且你可能期望第一次使用这个资源的线程来完成它的初始化工作。一个once_flag类型(它的准确类型由平台本身决定)和这个call_once函数能够保证多个线程不会重复地初始化同一个对象。但是你不得不做两件事。

首先,使用BOOST_ONCE_INIT宏来初始化这个once_flag类型的对象。这个宏的具体值由平台本身决定。示例12-5中,类Conn代表某种类型的连接(数据库、网络套接字、硬件等),我期望这个连接只初始化一次,尽管多个线程可能都会初始化它。常常当你想动态地装载一个库时这种情况就会出现,这个库可能是在一个应用程序的配置文件中指明的。这个once_flag是一个静态类变量,因为我仅期望初始化一次,而不管这个类可能有多个实例。因此,我给这个变量赋一个BOOST_ONCE_INIT值作为起始值,如下所示:

boost::once_flag Conn::initFlag_ = BOOST_ONCE_INIT;

然后,在我的工作函数中,我调用call_once函数,它同步对这个initFlag_变量的访问,这样就禁止了对这个变量的并发访问。我给这个函数传递了两个参数:

boost::call_once(Conn::init, Conn::initFlag_);

第一个参数用来做初始化函数的地址。第二个参数就是这个标志。这样的话,多个线程都可以初始化这个Conn类,但是只有一个会成功。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论