【发布时间】:2023-03-27 17:35:02
【问题描述】:
我正在制作一个客户端服务器应用程序,服务器有一个 GUI。我正在使用 Qt。 对于通信,我使用管道。
我已将服务器应用程序分为后端和 GUI。后端有一个 PipeServer 类,在 GUI 中,我重写了 onReceiveMessage 等函数。
在我决定添加 std::queue 作为基类成员之前,一切正常。
在应用程序开始时,我遇到了一个异常,经过检查,我的队列似乎不是以 0 个元素开始的。事实上,队列似乎根本没有初始化。有两种可能性:可能是因为我的 GUI 类继承了 2 个类,并且不知何故第二个基类,即我的 PipeServer 没有正确初始化其成员,或者可能是因为 pipeServerGUI 对象被移动到不同的线程QT。
关于如何解决这个问题的任何想法?
相关代码:
class HookServer
{
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
public:
std::queue<std::string> messages;
int init(std::string pipename);
int run();
virtual void onNewConnection() {};
virtual void onReceiveMessage(std::string message) {};
};
class HookServerGUI : public QObject, public HookServer
{
Q_OBJECT
void onReceiveMessage(std::string message);
void onNewConnection();
public slots:
void doWork() {
init("\\\\.\\pipe\\hookpipe");
run();
}
signals:
void signalGUI(QString message);
};
//GUIServerCreation
QThread *thread = new QThread;
HookServerGUI* worker = new HookServerGUI;
QObject::connect(worker,SIGNAL(signalGUI(const QString&)),this,SLOT(processMessage(const QString&)));
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
编辑:
异常是访问冲突异常。它发生在这部分代码中:
VOID HookServer::GetAnswerToRequest(LPPIPEINST pipe)
{
onReceiveMessage(pipe->chRequest);
if(!messages.empty())
{
std::string s = messages.front();
messages.pop();
strcpy(pipe->chReply,s.c_str());
pipe->cbToWrite = strlen(s.c_str()+1);
}
}
由于 messages.empty() 返回了一个巨大的数字,它尝试读取第一个对象并以某种方式失败。
也没有 PipeServerGUI 构造函数。
编辑2:
我通过在new HookServerGUI(); 后面加上括号解决了部分问题
问题是该函数仍然不起作用,并引发访问冲突异常。它发生在 front() 行。在调试器中检查时,该函数确实有 1 个元素,所以不是因为它是空的。有什么想法吗?
EDIT3:
在第二次运行时,不幸的是 queue.size() 仍然不正确。对我来说,这就像一场数据竞赛。
【问题讨论】:
-
我认为您的两个选项中的任何一个都不可能成为候选人。 HookServer 没有实现构造函数,因此默认构造函数应该调用其成员的默认构造函数(即 std::queue)。我看不出线程如何成为问题的一部分,因为 HookServerGUI 要么被构造,要么没有。错误在哪里?是在 HookServerGUI 的构造函数期间吗?异常类型是什么?
-
看来我部分解决了问题,我没有在
new HookServerGUI后面加括号。 -
GetAnswerToRequest() 是一个私有函数。谁叫它?也许您应该尝试在 HookServer 中创建构造函数和析构函数并记录一些内容或在其中放置断点,以确保在调用此函数之前您的对象正在被创建而不是被删除。
-
@sbaker 它在 run() 函数中被调用。现在我将队列更改为字符串,并将其显式设置为空字符串。
-
风格挑剔:
Qt::QueuedConnection中的invokeMethod是不必要的,自动连接将正常工作。QObject::connect可以传递规范化签名,所以SIGNAL(signalGUI(QString))和SLOT(processMessage(QString))就足够了——这样写的更少。 slot 方法的签名应该是void signalGUI(const QString &)- 以这种方式在共享字符串数据上保存detach()。
标签: c++ qt class initialization