0

我正在用 Qt 编写一个应用程序以部署在 Symbian S60 平台上。不幸的是,它需要有蓝牙功能——没有什么真正先进的,只是简单的 RFCOMM 客户端套接字和设备发现。确切地说,该应用程序有望在两个平台上运行 - Windows PC 和上述 S60。

当然,由于 Qt 缺乏蓝牙支持,它必须使用原生 API 进行编码——Windows 上的 Winsock2 和 S60 上的 Symbian C++——我正在编写一个简单的抽象层。我对 Symbian 上的发现部分有一些问题。

抽象层中的发现调用应该同步工作 - 它阻塞直到发现结束并将所有设备作为QList. 我现在没有确切的代码,但我有类似的东西:

RHostResolver resolver;
TInquirySockAddr addr;
// OMITTED: resolver and addr initialization

TRequestStatus err;
TNameEntry entry;
resolver.GetByAddress(addr, entry, err);
while (true) {
    User::WaitForRequest(err);
    if (err == KErrHostResNoMoreResults) {
       break;
    } else if (err != KErrNone) {
        // OMITTED: error handling routine, not very important right now
    }

    // OMITTED: entry processing, adding to result QList

    resolver.Next(entry, err);
}
resolver.Close();

是的,我知道那User::WaitForRequest邪恶的,像 Symbian 一样编码,我应该使用活动对象,等等。但这不是我需要的。我需要一种简单的同步方式来进行设备发现。

上面的代码确实有效。然而,有一个怪癖 - 我想在发现期间有一个超时。也就是说,我希望发现时间不超过 15 秒——在函数调用中进行参数化。我试图做这样的事情:

RTimer timer;
TRequestStatus timerStatus;
timer.CreateLocal();

RHostResolver resolver;
TInquirySockAddr addr;
// OMITTED: resolver and addr initialization

TRequestStatus err;
TNameEntry entry;

timer.After(timerStatus, timeout*1000000);

resolver.GetByAddress(addr, entry, err);
while (true) {
    User::WaitForRequest(err, timerStatus);

    if (timerStatus != KRequestPending) { // timeout
        resolver.Cancel();
        User::WaitForRequest(err);
        break;
    }

    if (err == KErrHostResNoMoreResults) {
        timer.Cancel();
        User::WaitForRequest(timerStatus);
        break;
    } else if (err != KErrNone) {
        // OMITTED: error handling routine, not very important right now
    }

    // OMITTED: entry processing, adding to result QList

    resolver.Next(entry, err);
}
timer.Close();
resolver.Close();

这段代码有点用。更重要的是,它的工作方式在功能上是正确的——超时有效,到目前为止发现的设备被返回,如果发现更早结束,那么它会在不等待计时器的情况下退出。问题是 - 它在程序中留下了一个杂散的线程。这意味着,当我退出我的应用程序时,它的进程仍然在后台加载,什么都不做。而且我不是那种会满足于“修复”的程序员类型,比如让“退出”按钮终止进程而不是优雅地退出。留下一个杂散的线程似乎是一个太严重的资源泄漏。

有没有办法解决这个问题?我不介意从头开始重写所有内容,即使使用完全不同的 API(只要我们谈论的是原生 Symbian API),我只是希望它能够工作。我已经阅读了一些关于活动对象的内容,但它似乎不是我需要的,因为我只需要它来同步工作......在更大的变化的情况下,我将不胜感激更详细的解释,因为我Symbian C++ 的新手,我真的不需要掌握它——这个小蓝牙模块可能是我在可预见的将来需要在其中编写的所有内容。

提前感谢您的帮助!:)

4

2 回答 2

0

你的代码对我来说看起来不错。您错过了不使用您发出的所有请求的常见陷阱。假设您还取消了计时器并在User::WaitForRequest(timerStatus)内部进行了错误处理,它应该可以工作。

我猜您担心的是您的主线程无法请求该线程退出。您可以大致按如下方式执行此操作:

  • TRequestStatus当你的主线程创建它时,将指向 a 的指针传递到线程中。打电话给这个exitStatus
  • 当你做的时候User::WaitForRequest,还等着exitStatus
  • 主线程bluetoothThread.RequestComplete(exitStatus, KErrCancel)想要子线程退出时会做一个,主线程创建bluetoothThreadRThread对象在哪里。
  • 在子线程中,当exitStatus发出信号时,退出循环以终止线程。您需要确保取消并使用计时器和蓝牙请求。
  • 主线程应该做一个bluetoothThread.Logon并等待信号等待蓝牙线程退出。

可能会有一些更微妙的地方来正确处理所有错误情况等等。

我希望我不会在这里完全吠错树...

于 2010-07-27T21:24:31.387 回答
0

问题已经得到解答,但是......如果您使用活动对象,我建议您使用嵌套的活动调度程序(CActiveSchedulerWait 类)。然后,您可以将它传递给您的活动对象(用于计时器的 CPeriodic 和用于蓝牙的其他一些 CActive),其中一个将在其 RunL() 方法中停止此嵌套调度程序。不仅如此,通过这种方法,您的调用对于调用者来说变得同步,并且您的线程将在执行调用后优雅地关闭。

如果您对该解决方案感兴趣,请搜索 CActiveSchedulerWait 的示例,或者直接问我,我会给您一些代码示例。

于 2010-08-04T07:58:57.597 回答