您的位置:首页 > 编程语言

Symbian编程总结-基础篇-活动对象正解(4)-异步函数的同步调用

2012-10-07 17:55 281 查看
本文章由杨芹勍原创,如需转摘请注明出处。谢谢!

        在上一节里我们深入了解了活动对象、活动调度器及异步函数服务器的工作原理及运行机制,想必大家对活动对象的机制及体系结构的运用已经了如指掌。但是大家有没有觉得异步函数使用起来比较麻烦呢?难道非要使用活动对象,非得以"异步"的方式调用异步函数吗?这一节将为大家解决这个问题:异步函数的同步使用。

 

一、使用CActiveSchedulerWait类

        在以前的文章"Symbian编程总结-界面篇-打开jpeg/gif/png图像"里我们已经看到了CActiveSchedulerWait类的使用方法,在此我再详细介绍一下。

        很多初学者在开始时会将CActiveScheduler和CActiveSchedulerWait类弄混,CActiveScheduler是活动对象的调度器,而CActiveSchedulerWait可以简单的理解为一个当前线程的阻塞器:

调用CActiveSchedulerWait::Start()方法时,线程阻塞;

调用CActiveSchedulerWait::AsyncStop()方法时,请求停止对线程的阻塞

        因此,我们在不修改原来活动对象代码的情况下,只要简单的在异步函数调用方法后加上"CActiveSchedulerWait::Start()",在活动对象的RunL方法的开头加入"CActiveSchedulerWait::AnsycStop()"就可以了。

        针对上一节教程介绍的控制台应用程序,我们对以下几个方法(下划线为修改部分)进行修改:

 

点击此处下载源代码

 

CActiveSchedulerWait* iWait;

 

void CMyActiveObject::ConstructL()

   
{

    User::LeaveIfError(iTimer.CreateLocal()
); // Initialize timer

    CActiveScheduler::Add( this); //
Add to scheduler

 

    iWait = new (ELeave)CActiveSchedulerWait;

   
}

 

CMyActiveObject::~CMyActiveObject()

   
{

    Cancel(); //
Cancel any request, if outstanding

    iTimer.Close(); //
Destroy the RTimer object

    //
Delete instance variables if any

 

    if (iWait->IsStarted())

        {

        iWait->AsyncStop();

        }

 

    delete iWait;

    iWait =
NULL;

   
}

 

void CMyActiveObject::StartL(TTimeIntervalMicroSeconds32 aDelay)

   
{

    Cancel(); //
Cancel any request, just to be sure

 

    iTimer.After(iStatus,
aDelay); // Set for later

    SetActive(); //
Tell scheduler a request is active

 

    iWait->Start();
// 第1点

   
}

 

void CMyActiveObject::RunL()

   
{

    iWait->AsyncStop();
// 第2点

 

    TBuf<50> outputStr;

   
outputStr.AppendNum(iCount);

    iConsole.Write(outputStr);

    iConsole.Write(_L("\n"));

    iCount++;

   
}

 

    使用CActiveSchedulerWait的几点注意事项:

CActiveSchedulerWait必须结合活动对象使用,而且使用方法只有以上代码介绍的那一种;

Start方法和AsyncStop方法必须成对出现;

程序退出时要检查CActiveSchedulerWait是否在IsStarted()状态,如果是则调用AsyncStop方法。否则程序不能正常退出;

CActiveScheduler类内部有自己的静态指针,提供的静态方法都调用了内部的静态指针。而CActiveSchedulerWait类没有内部静态指针,方法也不是静态的,我们必须自己管理CActiveSchedulerWait类的全局指针,在这点上程序要经过良好的设计。

 

二、使用User::WaitForRequest方法

    如果不想使用活动对象,也不想使用难于管理的CactiveSchedulerWait,你可以使用User::WaitForRequest方法。以下是User::WaitForRequest方法的原型:

IMPORT_C static void WaitForRequest(TRequestStatus&
aStatus); 

        此方法将等待异步函数服务器返回的信号量,然后匹配aStatus参数。如果接收到的信号与参数aStatus一一匹配,则跳过阻塞进入下一行代码,否则继续阻塞线程直到aStatus对应的信号通知返回。

User::WaitForRequest还有一个重载的方法,它可以监视两个信号的通知:

IMPORT_C static void WaitForRequest(TRequestStatus&
aStatus1,TRequestStatus&
aStatus2);

         有了User::WaitForRequest,异步函数使用起来就变得非常方便,我们不需要创建活动对象,也不需要创建成员变量TRequestStatus,只需要声明局部的TRequestStatus、局部的异步函数类,在异步函数调用之后,加入User::WaitForRequest(status),就能够使线程阻塞在User::WaitForRequest处直到status对应的异步函数处理完成。

LOCAL_C void DoTestL()

   
{

    RTimer timer;

   
CleanupClosePushL(timer);

    User::LeaveIfError(timer.CreateLocal());

   

    TRequestStatus status(KRequestPending);

   

    // 调用异步方法并将status传入

   
timer.After(status,
1000000);

   

    // 等待status对应的信号量,此处用了User::WaitForRequest方法将异步方法的调用模拟成同步

    User::WaitForRequest(status);

    CleanupStack::Pop(&timer);

   
}

 

LOCAL_C void MainL()

   
{

    TInt n
= 0;

    TBuf<10> str;

   
_LIT(KNewLine, "\n");

   

   
FOREVER

       
{

       
DoTestL();

       
str.Num(n);

       
n++;

       

       
console->Write(str);

       
console->Write(KNewLine);

       
}

   
}

 

三、使用User::WaitForRequest方法的问题

        User::WaitForRequest有时候不会正常运行,如:CImageDecoder::Convert方法:

IMPORT_C virtual void Convert(TRequestStatus*
aRequestStatus, CFbsBitmap&
aDestination, CFbsBitmap&
aDestinationMask, TIntaFrameNumber
= 0); 

        最后一个参数必须为EOptionAlwaysThread,User::WaitForRequest才能正常执行,个人认为CImageDecoder::Convert如果没有加EOptionAlwaysThread参数的时候是使用"长线任务"(将在下一节介绍)实现的。所以,CImageDecoder::Convert方法应该按照如下方法调用:

    TRequestStatus status(KRequestPending);

    CImageDecoder*
decoder = CImageDecoder::FileNewL(iFs,
aFileName, KMIMEType);

   

   
decoder->Convert(&status,
aBitmap, CImageDecoder::EOptionAlwaysThread);

    User::WaitForRequest(status);

   

    delete decoder;

   
decoder = NULL;

 

四、小结

        本文介绍了在如果将异步函数同步使用。其实在Symbian的早期编程中还有一种异步函数的同步方法,那就是在异步函数调用后使用CActiveScheduler::Start()方法嵌套活动调度器。但是这种方法已经被Symbian 7.0后的CActiveSchedulerWait替代,在此处就不再介绍。在下一节里将介绍活动对象的长线任务(Long-Running
Task)。

        另:在介绍活动对象的专题里涉及到很多Symbian OS的客户/服务器架构的知识,我会在近期另外开一个专题讲解,请大家耐心等待。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐