我有一个方法ConnectionManager
的类get_wifi_ssids()
必须返回一个SSID列表。问题是需要使用那些SSID信号和插槽,但我无法找到一种方法来检索该信息而不先退出该方法。
以下是从最低级别到最高级别使用的类的层次结构。
/** Controls wireless network card by commanding a software component "connman" via DBus. */
class WifiController : QObject {
Q_OBJECT
public:
void scan();
}
/** Low level interface to network interfaces. */
class NetworkController : QObject {
Q_OBJECT
public:
void scan_for_wifi() {
wifi_controller.scan();
// When scan is finished it sends the
// NetworkTechnology::scanFinished signal.
}
// Gets info from cache. This cache is updated when a `scan()` happens.
QList<AccessPointInfo> get_available_access_points;
private:
WifiController wifi_controller;
}
/** High level interface to network interfaces. */
class ConnectionManager {
public:
QList<QString> get_wifi_ssids() {
netCtrlr.scan();
// PROBLEM HERE: How do I wait for the `scanFinished` signal here, then
// continue execution and return the SSIDs from the recently-updated
// cache?
QList<AccessPointInfo> APs { netCtrlr.get_available_access_points() };
QList<QSitrng> ssids { parseAPInfo(APs) };
return ssids;
}
private:
NetworkController netCtrlr;
}
我的整个应用程序都在一个线程中。 “connman”由WifiConroller
通过DBus命令,它是一个单独的进程,因此很明显在一个单独的线程中。 GUI在一个单独的过程中运行,我的应用程序通过DBus与它通信。
根据this answer中的评论,QEventLoop
是一个糟糕的解决方案,因为它不打算在生产中使用,而且更像是黑客攻击。
答案 0 :(得分:5)
由于扫描操作是异步的,因此您无法真正拥有扫描SSID并返回它们的方法,因为等待扫描完成是一个阻塞操作。阻塞操作会阻止事件循环工作,并且信号信息将被处理。
您可以在get_wifi_ssids
方法中使用本地事件循环,但这会阻止应用程序的其余部分工作。如果WiFi扫描中有任何挂断,程序将在其中冻结。
相反,重新设计类以便在需要时启动扫描,get_wifi_ssids
返回接入点的最新信息。
答案 1 :(得分:2)
您可以使用本地QEventLoop
:
QList<QString> get_wifi_ssids() {
QEventLoop event;
// Stop event loop on signal
connect(&netCtrlr, SIGNAL(scanFinished()), &event, SLOT(quit()));
netCtrlr.scan();
// run event loop
event.exec();
QList<AccessPointInfo> APs { netCtrlr.get_available_access_points() };
QList<QString> ssids { parseAPInfo(APs) };
return ssids;
}