TAO教程之三:介绍-改进服务端,通过POA策略之显示激活和用户自定义对象ID...

本文探讨了如何通过使用CORBA的POA策略(如USER_ID和NO_IMPLICIT_ACTIVATION),来改进服务端的扩展性和对象管理。通过具体实例说明了如何创建子POA、激活对象,并实现了股票工厂的服务,同时讨论了对象内存管理和引用计数。

3.介绍-改进服务端,通过POA策略之显示激活和用户自定义对象ID

介绍——改善服务端

在本节,我们将在之前提到的“简单服务器”之上进行改进。我们将会讨论如何使把POA策略赋给对象ID。

在先前的示例中,我们用了 Quoter_Stock_Factory_i 的两个域来表示两支股票。如果我们想创建上百支股票,那么这种方法就缺少扩展性。我们需要用某个集合来保持对股票对象的跟踪,比如为股票符号建立索引。一种解决办法是使用STL map或与之差不多的集合类,但这样明显太浪费了。毕意,ORB已经以对象ID为索引建立了对象的集合。如果仅能自己选择ID,那么我们的问题就能得已解决。一个好消息是:POA允许这样做;一个坏消息是我们必须创建子POA。那这是为什么呢?这是因为RootPOA的ID是被ORB分配了的,我们不想要与它们冲突。此外,创建一个独立的POA比管理它更容易,因为多个应用程序的组件可以获得它们自己的POA,它们能被视为私有的命字空间。

子POA的创建

如前所述,我们可以访问RootPOA:

CORBA::Object_var poa_object =
orb->resolve_initial_references ("RootPOA");
PortableServer::POA_var poa =
PortableServer::POA::_narrow (poa_object.in ());

现在我们为子POA创建策略。在这个应用场景下,我们想使用USER_ID策略,这样就可以把它赋自己的这些ID。我们还想使用 NO_IMPLICIT_ACTIVATION 策略,以便于对我们的POA有更多的控制。POA具有许多我们可以控制的策略,但我们在示例中只使用默认的策略。在$TAO_ROOT/examples/POA/目录下有许多示例演示了如何使用这些策略。

策略存储在序列中的,所以我们首先创建序列并初始化它的长度。

CORBA::PolicyList policies (2);
policies.length (2);

接下来我们创建策略:

policies[0] =
poa->create_id_assignment_policy (PortableServer::USER_ID);
policies[1] =
poa->create_implicit_activation_policy (PortableServer::NO_IMPLICIT_ACTIVATION);

再然后我们创建子POA:

PortableServer::POA_var stock_factory_poa =
poa->create_POA ("Stock_Factory_POA",
poa_manager.in (),
policies);

注意的是,我们与RootPOA共用了POA管理器,于是我们只需要用一个POA管理就可以控制这两个POA的状态。新的POA复制了策略,所以我们为了避免内存泄漏,所以需要销毁它们。

for (CORBA::ULong i = 0; i != policies.length (); ++i)

{
policies[i]->destroy ();
}

在子POA中激活对象

现在我们必须使用这个POA来激活股票对象了。为了使示例简化,我们假设我们可以从标准输入设备(stdin)中读入这些股票信息,比如这样:

while (!std::cin.eof () && std::cin.peek () != EOF)

{
const int max_symbol_length = 8;
char symbol[max_symbol_length];
const int max_full_name_length = 64;
char full_name[max_full_name_length];
double price;
std::cin.getline (symbol, max_symbol_length, '\n');
std::cin.getline (full_name, max_full_name, '\n');
std::cin >> price;
std::cin.ignore (1, '\n');
// The interesting stuff goes here!
}

为每个符号、全称和价格的三元组中, 我们创建股票实现的对象:

PortableServer::ServantBase_var servant =
new Quoter_Stock_i (symbol, full_name, price);

ServantBase_var 充当的角色很象自动指针,在发生异常的情况下,它可以小心的管理对象的回收操作。这次我们不能使用_this() 来激活对象,这是因数我们要想创建自己对象ID:

PortableServer::ObjectId_var oid =
PortableServer::string_to_ObjectId (symbol);

然后我们通过id来激活对象:

stock_factory_poa->activate_object_with_id (oid.in (),
servant.in ());

请小心,不要在这些对象上调用_this(),如果这样就会在RootPOA中激活它们,被激活了两次!虽然在不同的POA中(甚于有时还在同一个POA中)多次激活一个对象是完全合法的,它是在现在的应用情景中我们并不需要这样做。

修改Stock Factory

现在我们必须实现Stock Factory的不同版本。我们传一个子POA的引用到构造函数中并维护这个引用:

class Quoter_Stock_Factory_i : public POA_Quoter::Stock_Factory
{
public:
Quoter_Stock_Factory (PortableServer::POA_ptr stock_factory_poa)
: stock_factory_poa_ (PortableServer::POA::_duplicate (stock_factory_poa))
{}
Quoter::Stock_ptr get_stock (const char *symbol)
throw (Quoter::Invalid_Stock_Symbol);
private:
PortableServer::POA_var stock_factory_poa_;
};

注意,我们复制了POA,这样才遵从惯用的CORBA对输入参数的内存管理规则。尽管构造函数并不是CORBA操作,这样做我们可以把这个规则使用得更广泛,如果我们坚持使用CORBA这套规则时可以减少误解。

get_stock 操作的实现更为有趣。首先我们依据符号创建对象的ID:

Quoter::Stock_ptr
Quoter_Stock_Factory_i::get_stock (const char *symbol)
throw (Quoter::Invalid_Stock_Symbol)
{
PortableServer::ObjectId_var oid =
PortableServer::string_to_ObjectId (symbol);

接下来在POA中查找对象的ID:

try {
CORBA::Object_var tmp =
this->stock_factory_poa_->id_to_reference (oid.in ());

最后将对象的引用narrow到正常的类型并返回它:

return Quoter::Stock::_narrow (tmp.in ());
}

要是符号无效,POA就找不对正确的对象ID,只好抛出异常:

catch (PortableServer::POA::ObjectNotActive &) {
throw Quoter::Invalid_Stock_Symbol ();
}
}

股票对象的内存管理

迄今为止,我们还尚为讨论伺服代码(servants)的内存管理问题。现在是讨论它的最好时机了,因为股票对象已完全授控于POA了。POA为伺服代码提供了引用计数。你并不需要使用引用计数,如果你遵从了这一点,那绝大多数的内存管理就相当的简单了。那为什么不是所有的时候都可以不使用引用计数呢?那是因为有的应用程序不需要它。举例来说,我们先前的简单服务不需要任何复杂的对象管理,于是所有的对象都是在栈(stack)上创建的。

如果想在POA中使用引用计数,你必须重载_add_ref() 和remove_ref() 这两个方法用来增加或减少引用的数目。 一旦数目回到0,你就可以安全的删除对象(但要记住,计数数目是从1开始的!)。

把这些方法实现为线程安全是一件繁琐的工作。为了减化这个工作,我们混合使用了PortableServer::RefCountServantBase 这个作为基类,像这样:

class Quoter_Stock_i
    :  public virtual POA_Quoter::Stock,
       public virtual PortableServer::RefCountServantBase
{
public:
  Quoter_Stock_i (const char *symbol,
                  const char *full_name,
                  CORBA::Double price);
  // as before
};

TAO中PortableServer::RefCountServantBase 的实现也是线程安全的,于是你可以用这个技术在你的多线程服务中动态的销毁对象。您简单的委托POA来控制,一旦所有线程调用了对象中止,当休眠该对象时,POA将会调用 _remove_ref(),这样如果这个对象还在使用中就不会被删除。也请记住如果你要使用对象请增加它的引用记数。

练习

从简单服务的文件作如下修改:

  • Stock_i.h: 使用引用计数控制伺服代码的内存管理。
  • Stock_Factory_i.h: Apply the changes described above to use a child POA with the appropriate policies.
  • Stock_Factory_i.cpp: Apply the changes described above to use a child POA with the appropriate policies.
  • server.cpp: Create the child POA, initialize the stock objects from the stdin, and create the right stock factory class.

你能够使用相同的Quoter.idl, Stock_i.cpp 和MPC 文件.

解决方案

在你的解决方案在同下面的文件作比较:

Does this solution scale when the number of stock symbols is in the thousands or millions? Find out about Servant Locators and Servant Activators in the POA!

Testing

有一个简单的输入文件可用. 你可以使用简单客户端来检查结果:

$ server < stock_list.txt > ior_file
$ client file://ior_file AAAA BBBB MSFT RHAT CCCC

也测试一下无效的符号!

More Reading

The Henning and Vinoski CORBA book discusses POA policies in detail. Likewise, the Schmidt and Vinoski columns in C++ Report also include several articles about the POA. Finally, the TAO distribution includes examples that illustrate how to use the POA policies.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值