- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对 QThread 很陌生,我想用 Qt 制作一个多线程应用程序。网上资源很多,有的推荐子类化QThread,有的说不行,他们用的是moveToThread函数。我真的很困惑。也许这取决于需求,所以我正在写我的需求。
该软件将通过 UDP 协议(protocol)与设备通信。设备将收到的数据包作为 ACK 发送回发送方。由于 UDP 不可靠,我想通过检查设备的应答来增加通信的可靠性。我想给设备一点时间发送答案,如果没有收到答案(ACK 数据包),我想再次发送相同的数据包。如果出现错误的应答数据包(乱序数据包),我可以忽略它,无需重新排序。将有一些数据包(设备命令)将定期发送,例如每秒发送一次。
我想使用 QThread 在线程中进行所有通信。单击按钮将启动线程并开始通信(一些数据包将定期发送)。单击按钮将停止通信。
那我该怎么做呢?我只需要步骤。
编辑:
我已经实现了阻塞读写。我正在使用 moveToThread 函数将它移动到线程并启动线程。但我不知道这是否是适合我的用例的最佳方式。
我像下面这样一个接一个地发送一些数据报,例如:
int UDP::readCalibration(..)
{
while(readStatus() != 0);
// Send addr, read page command and read buffer command
// one after each
writeRegisterBlock(LOW_ADDR, CalibAddr, 2); // Blocking
writeRegister(CMD_Reg, READ_PAGE); // Blocking
readRegisterBlock(READ_BUF, data, 128); // Blocking
}
....
int UDP::writeRegisterBlock(...)
{
....// Build UdpPacket
return UDP_Send(UdpPacket, &ReceivePacket);
}
int UDP::writeRegister(...)
{
....// Build UdpPacket
return UDP_Send(UdpPacket, &ReceivePacket);
}
int UDP::readRegisterBlock(...)
{
....// Build UdpPacket
return UDP_Send(UdpPacket, &ReceivePacket);
}
// and UDP_Send function, this is the important part
int UDP::UDP_Send(QByteArray UdpPacket, QByteArray *ReceivePacket)
{
QByteArray Datagram;
QHostAddress SenderAddress;
quint16 SenderPort;
int UDP_RetVal = -1, timeOutCounter = -1, NrOfSend = -1, NrOfRecv = -1, retVal = -1;
bool pendingDatagram = false;
SetContinueToRecv(true); // sets a boolean variable with mutex
SetContinueToSend(true); // sets a boolean variable with mutex
while ((NrOfSend < MAX_RETRY) && GetContinueToSend())
{
NrOfSend++;
SetContinueToRecv(true); // start receiver loop
UDP_RetVal = udpSocket->writeDatagram(UdpPacket, DestinationIP, port);
if(UDP_RetVal < 0)
{
qDebug() << "udpSocket error";
}
else
{
while((NrOfRecv < MAX_RETRY) && GetContinueToRecv())
{
pendingDatagram = false;
while (!pendingDatagram && (timeOutCounter < TIMEOUT_MS))
{
msleep(SLEEP_MS);
timeOutCounter++;
pendingDatagram = udpSocket->hasPendingDatagrams();
}
if (timeOutCounter < TIMEOUT_MS)
{
Datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(Datagram.data(), Datagram.size(), &SenderAddress, &SenderPort);
//Compare only first 4 bytes, cmd, nr, addr
if((UdpPacket.mid(0, 4) == Datagram.mid(0, 4)) && (SenderAddress == DestinationIP) )
{
retVal = 0;
//Take only data , not commands
ReceivePacket->resize(Datagram.size()-4);
ReceivePacket->replace(0, Datagram.size()-4, Datagram.right(Datagram.size()-4));
SetContinueToRecv(false); // Break receiver while loop
SetContinueToSend(false); // Break sender while loop
}
else // Wrong packet
{
SetContinueToRecv(true); // try again to receive
timeOutCounter = -1;
qDebug() << "Wrong Packet.";
} // Wrong packet
}
else // Timeout
{
qDebug() << "Timeout maximum. NrOfSend: " << NrOfSend << " NrOfRecv: " << NrOfRecv;
timeOutCounter = -1;
SetContinueToSend(true); // try again to send
SetContinueToRecv(false);
} // Timeout
} // Receive loop
NrOfRecv = -1;
} // Succesfully sent
} // Send loop
if(NrOfSend == MAX_RETRY)
{
retVal = -1; // Could not send.
qDebug() << "Could not send";
}
return retVal;
}
如何用 readyRead 和 Timeout 函数替换阻塞函数?也许我必须保存发送的数据报,并且在超时时我必须将接收到的数据报与发送的数据报进行比较,如果相同,则数据包发送和接收正确。如果没有,我必须重新发送?
最佳答案
我强烈建议您使用异步 API QUdpSocket
类提供您的用例。
使用连接到 readyRead()
信号的插槽,并在该插槽内使用 readDatagram()
实际从套接字读取接收到的数据。为了发送数据,在任何你喜欢的地方使用 writeDatagram()
,它不会阻塞调用线程。
您可以阅读 Broadcast Receiver Example和 Broadcast Sender Example , 并编写类似的代码。
至于超时的事情,你可以有一个QTimer
它的 timeout()
信号连接到发送数据报的槽,以便它发送 它在指定时间内没有响应时继续发送数据包,并让计时器的 start()
在连接到 readyRead()
信号的槽中调用的方法(以便在每次收到数据报时重新启动计时器)。
要回答你关于多线程的问题,通常的简单使用方法是有一个派生自 QObject
的类,并实现需要在该类中执行的插槽,然后实例化一个新的 QThread
并对该对象调用 moveToThread()
到新的 QThread
。之后,当任何连接到该对象槽的信号被发出时,槽代码将在新线程中执行。
但是,值得注意的是,在 Qt 中有很多利用多线程的方法,每个用例都有其实现方式,请看这里 Multithreading Technologies in Qt .并且在您的用例中,根本不要使用多线程。
编辑:所以你无法上网,你实现了你的阻塞读写。 . .
I am moving it to a Thread using moveToThread function and starting the thread
首先,您必须确保在将 QObject
移动到新线程后,您不会直接调用使用阻塞 IO 的函数,而是通过连接一个向它发出信号并发出该信号,或者使用 QMetaObject::invokeMethod
。因为直接调用它会在调用者的线程中执行您的函数,这很可能是 GUI 线程,而这是我们不想做的事情。 . .
我可以看到您在 UDP::UDP_Send
中调用了 msleep
。请不要告诉我您的 UDP
类继承自 QThread
,请再次阅读我的回答以了解您应该从中派生什么。
似乎您正在通过每个 SLEEP_MS
调用其 hasPendingDatagrams
来轮询 QUdpSocket
。如果您要继续使用阻塞模式,请改用 waitForReadyRead
,这样线程将一直阻塞,直到 QUdpSocket
收到数据报为止。 . .
这些迹象表明您没有让您的代码在新线程中正确执行。 . .
附言:使用我第一次告诉你的异步方式重写你的代码,比修复你当前的代码要容易、简单和干净得多。只需阅读我链接的示例,如果您不明白,请随时询问它们。 . .
关于c++ - 需要帮助使用 QThread 的多线程应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35340933/
我是 C 语言新手,我编写了这个 C 程序,让用户输入一年中的某一天,作为返回,程序将输出月份以及该月的哪一天。该程序运行良好,但我现在想简化该程序。我知道我需要一个循环,但我不知道如何去做。这是程序
我一直在努力找出我的代码有什么问题。这个想法是创建一个小的画图程序,并有红色、绿色、蓝色和清除按钮。我有我能想到的一切让它工作,但无法弄清楚代码有什么问题。程序打开,然后立即关闭。 import ja
我想安装screen,但是接下来我应该做什么? $ brew search screen imgur-screenshot screen
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个简单的 python 客户端程序,它发送消息“hello world how are you”。服务器随后应接收消息,将
我有一个 shell 脚本,它运行一个 Python 程序来预处理一些数据,然后运行一个 R 程序来执行一些长时间运行的任务。我正在学习使用 Docker 并且我一直在运行 FROM r-base:l
在 Linux 中。我有一个 c 程序,它读取一个 2048 字节的文本文件作为输入。我想从 Python 脚本启动 c 程序。我希望 Python 脚本将文本字符串作为参数传递给 c 程序,而不是将
对于一个类,我被要求编写一个 VHDL 程序,该程序接受两个整数输入 A 和 B,并用 A+B 替换 A,用 A-B 替换 B。我编写了以下程序和测试平台。它完成了实现和行为语法检查,但它不会模拟。尽
module Algorithm where import System.Random import Data.Maybe import Data.List type Atom = String ty
我想找到两个以上数字的最小公倍数 求给定N个数的最小公倍数的C++程序 最佳答案 int lcm(int a, int b) { return (a/gcd(a,b))*b; } 对于gcd,请查看
这个程序有错误。谁能解决这个问题? Error is :TempRecord already defines a member called 'this' with the same paramete
当我运行下面的程序时,我在 str1 和 str2 中得到了垃圾值。所以 #include #include #include using namespace std; int main() {
这是我的作业: 一对刚出生的兔子(一公一母)被放在田里。兔子在一个月大时可以交配,因此在第二个月的月底,每对兔子都会生出两对新兔子,然后死去。 注:在第0个月,有0对兔子。第 1 个月,有 1 对兔子
我编写了一个程序,通过对字母使用 switch 命令将十进制字符串转换为十六进制,但是如果我使用 char,该程序无法正常工作!没有 switch 我无法处理 9 以上的数字。我希望你能理解我,因为我
我是 C++ 新手(虽然我有一些 C 语言经验)和 MySQL,我正在尝试制作一个从 MySQL 读取数据库的程序,我一直在关注这个 tutorial但当我尝试“构建”解决方案时出现错误。 (我正在使
仍然是一个初学者,只是尝试使用 swift 中的一些基本函数。 有人能告诉我这段代码有什么问题吗? import UIKit var guessInt: Int var randomNum = arc
我正在用 C++11 编写一个函数,它采用 constant1 + constant2 形式的表达式并将它们折叠起来。 constant1 和 constant2 存储在 std::string 中,
我用 C++ 编写了这段代码,使用运算符重载对 2 个矩阵进行加法和乘法运算。当我执行代码时,它会在第 57 行和第 59 行产生错误,非法结构操作(两行都出现相同的错误)。请解释我的错误。提前致谢:
我是 C++ 的初学者,我想编写一个简单的程序来交换字符串中的两个字符。 例如;我们输入这个字符串:“EXAMPLE”,我们给它交换这两个字符:“E”和“A”,输出应该类似于“AXEMPLA”。 我在
我需要以下代码的帮助: 声明 3 个 double 类型变量,每个代表三角形的三个边中的一个。 提示用户为第一面输入一个值,然后 将用户的输入设置为您创建的代表三角形第一条边的变量。 将最后 2 个步
我是新来的,如果问题不好请见谅 任务:将给定矩阵旋转180度 输入: 1 4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 输出: 16 15 14 13 12 11
我是一名优秀的程序员,十分优秀!