【问题标题】:WaitForRequest with Timeout crashes超时的 WaitForRequest 崩溃
【发布时间】:2009-09-23 15:01:39
【问题描述】:

编辑:我现在对我的代码进行了一些编辑,以便对“所有”代码有一个粗略的了解。也许这 可能有助于识别问题;)

我已经集成了以下简单的代码片段,如果有数据则取消计时器 从 TCP 套接字读取,否则取消从套接字读取的数据

// file tcp.cpp
void CheckTCPSocket()
{
TRequestStatus iStatus;
TSockXfrLength len;

int timeout = 1000;
RTimer timer;
TRequestStatus timerstatus;

TPtr8 buff;
iSocket.RecvOneOrMore( buff, 0, iStatus, len );

timer.CreateLocal();

timer.After(timerstatus, timeout);
// Wait for two requests – if timer completes first, we have a
// timeout.
User::WaitForRequest(iStatus, timerstatus);

if(timerstatus.Int() != KRequestPending)
{
  iSocket.CancelRead();
}
else
{
  timer.Cancel();
}
timer.Close();
}

// file main.cpp
void TestActiveObject::RunL()
{
  TUint Data;
  MQueue.ReceiveBlocking(Data);
  CheckTCPSocket();
  SetActive();
}

这部分是在活动对象中执行的,由于集成了上面的代码片段,我总是得到内核恐慌: E32User-CBase 46:这个恐慌是由一个活动的调度程序,一个 CActiveScheduler 引发的。它是由杂散信号引起的。

在执行这段代码之前,我的代码从未遇到任何问题;代码执行良好,因为从套接字读取数据并且 然后计时器被取消并关闭。我不明白计时器对象如何对 AO 产生任何影响。

如果有人能指出我正确的方向,那就太好了。

谢谢

【问题讨论】:

    标签: c++ symbian active-objects


    【解决方案1】:

    这可能是另一个活动对象完成(不是这两个之一)或未调用 SetActive() 的问题。见Forum Nokia。没有看到你所有的代码很难说!

    BTW User::WaitForRequest() 几乎总是是个坏主意。见why here

    【讨论】:

    • 感谢您的回答。问题是,我有一个要遵循的请求/响应协议,这意味着我需要等待传入的响应才能处理下一个请求;因此 WaitForRequest() 包含!
    • 你不需要 WaitForRequest 来实现它。一个 Active Object 状态机肯定能解决问题。应该不惜一切代价避免 WaitForRequest(在 10 年的 Symbian OS 编程中,我从未使用过它:-)
    • 切斯凯文,但我正在编写用于测试目的的代码,所以它一定不是绝对有效的。让某些东西快速运行很重要,希望能快速解决我的问题。不想重写整个实现;)
    • 我看到你已经更新了代码......现在它开始变得清晰了。您在 Active Object RunL() 中调用 WaitForRequest()... 会发生坏事 - 您正在阻塞 Active Scheduler 循环,但在该循环中完成了对象!无论是否测试代码,您都必须重构代码。例如将计时器包装在回调 AO 中,而不是在同一个活动对象中等待第二个 iStatus 类似的问题解决方案:discussion.forum.nokia.com/forum/… 永远不要在活动对象中使用 WaitForRequest()。
    • 此外,您可能会调用 SetActive() 而没有挂起的请求(如果计时器完成,您会取消套接字读取,但仍会调用 SetActive()) - 这将导致 CBase 46 恐慌。您在哪里看到 CBase 46 - 在 WaitForRequest() 调用或 SetActive() 中
    【解决方案2】:

    切勿混合活动对象和User::WaitForRequest()

    (嗯,几乎从来没有。当您确切地知道自己在做什么时,它可以没问题,但是您发布的代码表明您仍然需要学习。)

    当异步服务提供者使用RThread::RequestComplete() 向线程请求信号量发出信号时,您会遇到杂散信号恐慌,并且在带有User::WaitForAnyRequest() 的信号量上等待的活动调度程序尝试查找已完成的活动对象,因此可以调用其RunL(),但在其活动对象列表中找不到任何对象。

    在这种情况下,您有两个正在进行的请求,这两个请求都不受活动调度程序的控制(例如,不使用 CActive::iStatus 作为 TRequestStatus;在不涉及 CActive::iStatus 的对象上发出 SetActive()在异步请求中是代码中的另一个错误,但不是杂散信号的原因)。您等待其中任何一个以WaitForRequest() 完成,但根本不要等待另一个完成。另一个请求的完成信号会转到活动调度程序的WaitForAnyRequest(),从而产生杂散信号。如果你取消一个请求,你仍然需要等待线程请求信号量。

    最好的解决方案是将超时计时器也设为活动对象。看看CTimer 类。

    另一种解决方案是在尚未完成的请求上添加另一个WaitForRequest

    【讨论】:

    • 奇怪的是,当我只在代码中使用 User::WaitForRequest(iStatus) 语句并省略了计时器时,我从来没有遇到过问题。现在,当我使用 RTimer 和 User::WaitForRequest(iStatus, timerstatus) 时,我突然遇到了这个问题。我不应该一开始就遇到这个问题,还是只有当我有多个待处理请求时才会出现这种情况?
    • 感谢 laalto,是的,我同意我远非 Symbian 专家!好吧,我不得不承认这种行为让我感到惊讶。我想当我取消一个请求时,我不需要在以后的阶段考虑它。换句话说,我需要在定时器被取消的路径中添加另一个WaitForRequest,对吗?这样做时,我确保我处理了 Timer 的 RequestComplete() 并且我没有在 Active Object 中收到错误。
    • 基本上,我的代码中没有 timer.cancel,而是等待使用 User::WaitForRequest(timerstatus) 完成的请求,因为超时信号总是发生并且需要处理。从套接字读取的数据的故事是不同的,因为在这里我永远不会得到任何数据。在这里,我取消了原始代码中的请求
    • 是的,如果您有 n 个请求,您将获得满足 n 个 WaitForRequests 的 n 个完成。请求可以正常完成,也可以通过取消完成。实际上,学习正确使用活动对象并让活动调度程序为您等待是最容易的。
    【解决方案3】:

    您正在调用TestActiveObject::SetActive(),但没有调用任何将TestActiveObject::iStatus 设置为KRequestPending 的方法。这会造成杂散信号恐慌。

    代码中唯一的 iStatus 变量是 CheckTCPSocket() 方法的本地变量。

    【讨论】:

    • 这仅适用于 euser 的调试版本,例如winscw udeb 模拟器,而不是运行 release euser 的目标设备。
    • (同时假设对象已被 Add() 到活动调度器。)
    猜你喜欢
    • 1970-01-01
    • 2021-04-06
    • 2016-03-30
    • 2011-04-23
    • 2015-06-07
    • 2016-03-07
    • 2019-09-10
    • 1970-01-01
    • 2013-04-11
    相关资源
    最近更新 更多