Kdnssd 在发布模式 Qt c++ 下不工作

问题描述 投票:0回答:1

我在我的 qt cmake 项目中使用 KDNSSD,在 Windows 11 中使用 C++,由 bonjour 支持,它会在调试模式下发现并注册设备,但是当我在发布模式下编译项目时,它不再工作,我在不同的版本中看到的日志模式是,

调试模式


Both Browse and Register:

qt.core.qobject.connect: QObject::connect: Connecting from COMPAT signal (QSocketNotifier::activated(int))

发布模式


For Service Browse:


QObject::setParent: Cannot set parent, new parent is in a different thread
QSocketNotifier: Can only be used with threads started with QThread
qt.core.qobject.connect: QObject::connect: Connecting from COMPAT signal (QSocketNotifier::activated(int))
QObject::startTimer: Timers can only be used with threads started with QThread

For Register:

QSocketNotifier: Can only be used with threads started with QThread
qt.core.qobject.connect: QObject::connect: Connecting from COMPAT signal (QSocketNotifier::activated(int))

此日志显示在所有构建中

Exception thrown at 0x00007FFFFA004B2C (KernelBase.dll) in clipbird.exe: 0x8001010D: An outgoing call cannot be made since the application is dispatching an input-synchronous call.
onecore\com\combase\dcomrem\giptbl.cxx(1796)\combase.dll!00007FFFFC2054EC: (caller: 00007FFFFC21DE1D) ReturnHr(1) tid(3dec) 8000FFFF Catastrophic failure
onecore\com\combase\objact\actvator.cxx(1097)\combase.dll!00007FFFFC21DEB0: (caller: 00007FFFFC280364) ReturnHr(2) tid(3dec) 8000FFFF Catastrophic failure

首先,我没有直接使用线程,当我在 KDNSSD 源代码中看到 line 时,它使用旧的 SIGNAL 和 SLOT,所以

Connecting from COMPAT signal
似乎是合适的,但我不知道其他日志,尤其是在释放模式下。我的整个项目位于 github 特别是 服务寄存器服务浏览器 谢谢:)

服务登记

/**
 * @brief Construct a new Discovery Register object
 *
 * @param parent Parent object
 */
Register::Register(QObject* parent) : QObject(parent) {
  this->service = new KDNSSD::PublicService();
  this->service->setParent(this);

  // connect the signals to the slots
  const auto signal_r = &KDNSSD::PublicService::published;
  const auto slot_r   = &Register::OnServiceRegistered;
  connect(this->service, signal_r, this, slot_r);
}

/**
 * @brief Register the service
 *
 * @param callback Callback function to be called
 * when service Registered
 */
void Register::registerServiceAsync() {
  // Set the service name & other details
  this->service->setServiceName(constants::getMDnsServiceName().c_str());
  this->service->setType(constants::getMDnsServiceType().c_str());
  this->service->setPort(this->getPort());

  // publish the service Asynchronously
  this->service->publishAsync();
}

/**
 * @brief Stop the server
 */
void Register::unregisterService() {
  this->service->stop();
}

服务浏览器

/**
 * @brief Construct a new Discovery Discover object
 *
 * @param parent Parent object
 */
Discover::Discover(QObject* parent) : QObject(parent) {
  this->m_browser = new KDNSSD::ServiceBrowser(constants::getMDnsServiceType().c_str());
  this->m_browser->setParent(this);
}

/// @brief On Service Found
void Discover::OnServiceFound(KDNSSD::RemoteService::Ptr service) {
  // get the name of the device & lambda callback
  const auto myDevice = QString::fromStdString(constants::getMDnsServiceName());
  const auto callback = [&, service](const QHostInfo& info) {
    if (info.error() != QHostInfo::NoError || info.addresses().isEmpty()) {
      emit this->OnErrorOccurred(LOG("Unable to resolve service"));
      return;
    }

    auto host = info.addresses().first();
    auto port = quint16(service->port());
    this->onServerAdded({host, port});
  };

  // resolve the service
  if (!service->resolve()) {
    emit this->OnErrorOccurred(LOG("Unable to resolve service"));
    return;
  }

  // check if the service is mine
  if (service->serviceName() == myDevice) {
    return;
  }

  // lookup the host
  QHostInfo::lookupHost(service->hostName(), callback);
}

/// @brief On Service Removed
void Discover::OnServiceRemoved(KDNSSD::RemoteService::Ptr service) {
  // get the name of the device & lambda callback
  const auto myDevice = QString::fromStdString(constants::getMDnsServiceName());
  const auto callback = [&, service](const QHostInfo& info) {
    if (info.error() != QHostInfo::NoError || info.addresses().isEmpty()) {
      emit this->OnErrorOccurred(LOG("Unable to resolve service"));
      return;
    }

    auto host = info.addresses().first();
    auto port = quint16(service->port());
    this->onServerRemoved({host, port});
  };

  // resolve the service
  if (!service->resolve()) {
    emit this->OnErrorOccurred(LOG("Unable to resolve service"));
    return;
  }

  // check if the service is mine
  if (service->serviceName() == myDevice) {
    return;
  }

  // lookup the host
  QHostInfo::lookupHost(service->hostName(), callback);
}

/**
 * @brief Starts the discovery client by sending the
 * broadcast message
 *
 * @param interval Interval between each broadcast
 */
void Discover::startDiscovery() {
  // connect the browser signal to the slot of this class
  const auto signal_r = &KDNSSD::ServiceBrowser::serviceRemoved;
  const auto slot_r   = &Discover::OnServiceRemoved;
  connect(this->m_browser, signal_r, this, slot_r);

  // connect the browser signal to the slot of this class
  const auto signal_a = &KDNSSD::ServiceBrowser::serviceAdded;
  const auto slot_a   = &Discover::OnServiceFound;
  connect(this->m_browser, signal_a, this, slot_a);

  // start the browser
  this->m_browser->startBrowse();
}
c++ multithreading qt cmake bonjour
1个回答
-1
投票

您遇到的错误消息似乎与线程问题有关。由于编译器优化和/或不同的运行时环境,调试模式下的行为可能与发布模式不同。调试模式可能更宽松,这可能会导致工作正常,但在发布模式下,会应用更严格的规则,从而导致这些错误。

关键问题似乎是:

“QObject::setParent:无法设置父级,新父级位于不同的线程中” “QSocketNotifier:只能与以 QThread 启动的线程一起使用” “计时器只能与以 QThread 启动的线程一起使用” “由于应用程序正在调度输入同步调用,因此无法进行传出呼叫。” 让我们逐一讨论:

QObject::setParent:无法设置父级,新父级位于不同线程中: 当您尝试使用 QObject::setParent() 方法在线程之间移动对象,并且新的父对象与子对象位于不同的线程中时,会发生此错误。使用 Qt 时,每个对象通常应与其父对象属于同一线程。

您应该检查设置对象父对象的代码,并确保父对象和子对象属于同一线程。

QSocketNotifier:只能与以 QThread 启动的线程一起使用: QSocketNotifier 设计为与 QThread 一起使用,并且在您的发布版本中,线程行为可能会发生变化,从而导致此错误。同样,您应该检查使用 QSocketNotifier 的代码,并确保它是在 QThread 的上下文中使用的。

定时器只能与以 QThread 启动的线程一起使用: 该错误与定时器的使用有关。 Qt 中的定时器应该在 QThread 的上下文中使用。如果您的代码中运行任何计时器,请确保它们相对于线程正确使用。

“由于应用程序正在调度输入同步调用,因此无法进行传出呼叫。”: 这个错误有点棘手,它也可能与线程有关。这可能是由于尝试从主线程执行长时间运行或阻塞操作而导致的,这可能会导致无响应或死锁。检查主线程中是否正在执行任何冗长或阻塞操作,并考虑将它们移至单独的线程。

一般来说,确保所有 Qt 对象在同一线程上下文中创建、使用和销毁至关重要。混合来自不同线程的对象可能会导致未定义的行为,Qt 提供了各种机制(例如 QThread、QThreadPool 和 QTimer)来有效管理并发。

要调试线程问题,您可以尝试使用 Qt 的内置调试工具,例如 qDebug()、Q_ASSERT 和 QThread::currentThread() 来打印线程信息并识别线程使用中的任何不一致之处。

此外,查看发生错误的 KDNSSD 源代码可能会让您深入了解它如何管理线程,并可能提供有关如何解决问题的提示。

请仔细检查您的代码并确保正确处理线程和 Qt 对象以解决这些错误。

© www.soinside.com 2019 - 2024. All rights reserved.