Is Signal/Slot mechanism is faster than Queue mechanism? - c++

I am working on a Qt program that communicate with specific digital board with LAN and Serial Port, These packets should be read from LAN and send to other device connected to pc immediately. we have a problem with those packets come from serial port. we get these packets with emit on readyRead Signal and using readAll function for reading QByteArray inside the connected Slot. the problem is: delay on reading packets. I want to change the signal/slot mechanism to producer/costumer queue mechanism (using mutex for prevent critical section). Is queue mechanism faster than signal/slot or not?
Some code like below: this is not an executable function just present in pseudocode
func1Thread() //customer thread
{
while(!stopThread)
{
if(queueSize>0)
{
//parse packet
}
else
msleep(100);
}
}
func2Thread() //producer thread
{
while(!stopThread)
{
if(!socket.waitForReadyRead())
{
qByteArray ba= socket.readAll();
//enqueue here
}
}
}
thanks

Related

The slot of readMessageFromTCPServer could not be triggered sometimes after receiving message

I use Qt creator 5.5.1 in windows 7.
The compiler is VC 2010 32 bits.
I have written a socket client. It could connect well but sometimes its readyRead() signal could not be triggered after receiving message from server. So the readMessageFromTCPServer() slot could not be triggered and the thread could not run.
void MainWindow::on_pushBtn_LoadCfg_clicked()
{
if (tcpClient == NULL)
{
tcpClient = new QTcpSocket;
tcpClient->connectToHost(ui->txtIPServer->text(),ui->txtPortServer-
>text().toInt());
QObject::connect(tcpClient,SIGNAL(readyRead()),this,
SLOT(readMessageFromTCPServer()));
}
}
void MainWindow::readMessageFromTCPServer()
{
std::string r="start";
QByteArray qba;
qba= tcpClient->readAll();
if (qba.contains(r.c_str()))
{
cout<<"thread run";
}
}
When I tried to debug this program. I put a break point at this line: Sleep(800), but sometimes this slot could not be triggered after receiving message from socket server. And I have checked that the socket is still connected, why the slot could not be triggered?
There are some errors in your code. You will only have the slot triggered once.
Get rid of those Sleep commands. There is no good reason to use it if you are doing it in the main thread.
QByteArray qba= NULL; makes no sense. QByteArray qba; is ok.
while(1) means forever. You should break the loop at some point. Actually, you do not need this loop at all. Put the code inside this loop out of it and remove the loop. When the readyRead() signal is emitted, it means that there is some data to be read. You can readAll() that data chunk, do your stuff and return.
There is no guarantee that you will get your entire message in one round. So, in some circumstances, you may get "St" in one signal and "art" in another. So, you should implement your own buffering mechanism for such a situation. It may happen on big chunks of data. If you are sure that you are getting very short packages, then it's ok to rely on the internal buffer of QTCPSocket.

Serial Communication Timeout in QT with Arduino

I want to implement a timeout mechanism such that if the arduino doesn't read the command within one second, it results in a timeout and the new command is discarded and the program runs fine.
But right now, the program hangs if any new command is sent during the execution of the old one.
This is the timeout section of my code:
QByteArray requestData = myRequest.toLocal8Bit();
serial.write(requestData);
if (serial.waitForBytesWritten(waitTime)) {
if (serial.waitForReadyRead(myWaitTimeout)) {
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
emit this->response(response);
} else {
emit timeout(tr("Wait Read Request Timed Out %1")
.arg(QTime::currentTime().toString()));
}
} else {
emit timeout(tr("Wait Write Request Timed Out %1")
.arg(QTime::currentTime().toString()));
}
The timeout signal is connected to a slot that just prints the timeout message and does nothing.
How can I fix this so that I can achieve what I target?
You are using blocking approach to transmit data via serial port. Unless you are using threads I don't see possibility to send any additional data during execution of previous loop.
BTW: Your program, for example, will block indefinitely if Arduino manages to keep sending something within 10ms periods.
Add couple of QDebug() << "I'm here"; lines to check where your code gets stuck; it is possible that you are blocking somewhere outside code you pasted here. Alternative is to use debugger.
What if previous 'command' you tried to send is still in the buffer ? You'll end up filling output buffer. Check with QDebug how many bytes are in output buffer before writing more data to it. Buffer should be empty. (qint64 QIODevice::bytesToWrite() const).

Multiple client and single server handling

Will this approach work?
I am gonna simply present my code in simplified form for easier readability.
I am trying to implement a multiple client/one TCP server.
My listener will loop like this(as a thread) which handles connections
void WaitAndAcceptConnection(){
if(socket_TEMP = accept(sock_LISTEN, (SOCKADDR*)&ADDRESS, &AddressSize))
{
socketsManager.push_back(socket_TEMP);
currCount++;
std::cout<<"\n A connection was found!"<<std::endl;
send(socketsManager[currCount], "Welcome! you have connected to Athena Server", 46,NULL);
// cond.notify_one(); //notify the waiting thread
}
}
wherein i have..
std::vector<SOCKET> socketsManager; //handles socket
int currCount=-1; //keep track on the number of connections
If a client connected then currCount will be increased by one, in our case it's gonna be currCount = 0 and then socketsManager[0] will store the accept's return. If another one connected then currCount = 1 then socketsManager[1] will be its handler.
For sending and receiving data.
I am gonna make a for loop that will continue on iterating to check if there is a recv'd data(-1 or 0) for every sockets that is being handled by my program.
void WaitAndAcceptCommands(){
for(int i = 0; i<= currCount;i++){
int result = recv(socketsManager[i],&command,1,0);
if(result ==-1){
}
else if(result == 0){
}
else{
//process commands
}
}
}
Main will be something like this
Athena ath2; //instance of the server
std::cout<<"\n >Waiting for incoming connections..."<<std::endl;
//listener thread, just keep on LOOPING
std::thread connectionThread([&](){
while(1){
ath2.WaitAndAcceptConnection();
}
});
//handles all the inputs, JUST KEEP ON LOOPING
std::thread commandsThread([&](){
while(1){
ath2.WaitAndAcceptCommands();
}
});
connectionThread.join(); //stop
commandsThread.join(); //stop
I would gladly show the rest of my code but they are in a complete mess right now. I only wanted to present the idea if this will work and then i will continue on it, if not then i will reconsider another method. I plan on handling my connections through timeouts if i will ever have to drop a socket from my std::vector<SOCKET> socketsManager; by using remove. Is this a good method? if not then what are the issues?
I see a couple of problems with what you're doing:
You're pushing to socketsManager vector indefinitely. It won't be long before you run out of memory / file descriptors.
Protect access to socketsManager with some lock, else you can have race condition.
One way to do this is to use event loop:
Have one or more threads for doing I/O.
Each I/O thread operates on a list of open sockets.
It uses select() or poll() to figure out which socket amongst the set it is operating on has data available. Invokes the necessary callbacks with the data that was read.
Processing the data is handled by worker threads. The callback invoked one of the worker thread which processes the data.
References:
http://instagram-engineering.tumblr.com/post/121930298932/c-futures-at-instagram (see non-blocking IO section)

Broadcast large data with Qt sockets

I'm using QT. I need to broadcast data, so I try to use QUdpSocket. But data can be too big(after writeDatagram QUdpSocket::error returns DatagramTooLargeError). So I split data and call writeDatagram several times to the parts. But Received socket receive data only once, only first packet. Receive code is
connect(&m_socketReceiver, &QUdpSocket::readyRead, this, &LocalNetSharing::onDataRead);
void LocalNetSharing::onDataRead()
{
while (m_socketReceiver.hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(m_socketReceiver.pendingDatagramSize());
m_socketReceiver.readDatagram(datagram.data(), datagram.size());
//process data
}
}
From the Qt documentation about QUdpSocket Class :
Note: An incoming datagram should be read when you receive the
readyRead() signal, otherwise this signal will not be emitted for the
next datagram.
So it seems that you are not reading the entire datagram in each call of onDataRead.
You don't specify host and port in readDatagram. I am not sure if it is the reason but the correct form is :
while (m_socketReceiver.hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(m_socketReceiver.pendingDatagramSize());
m_socketReceiver.readDatagram(datagram.data(), datagram.size(), host, &port);
//process data
}

Emitting signal when bytes are received in serial port

I am trying to connect a signal and a slot in C++ using the boost libraries. My code currently opens a file and reads data from it. However, I am trying to improve the code so that it can read and analyze data in real time using a serial port. What I would like to do is have the analyze functions called only once there is data available in the serial port.
How would I go about doing this? I have done it in Qt before, however I cannot use signals and slots in Qt because this code does not use their moc tool.
Your OS (Linux) provides you with the following mechanism when dealing with the serial port.
You can set your serial port to noncanonical mode (by unsetting ICANON flag in termios structure). Then, if MIN and TIME parameters in c_cc[] are zero, the read() function will return if and only if there is new data in the serial port input buffer (see termios man page for details). So, you may run a separate thread responsible for getting the incoming serial data:
ssize_t count, bytesReceived = 0;
char myBuffer[1024];
while(1)
{
if (count = read(portFD,
myBuffer + bytesReceived,
sizeof(myBuffer)-bytesReceived) > 0)
{
/*
Here we check the arrived bytes. If they can be processed as a complete message,
you can alert other thread in a way you choose, put them to some kind of
queue etc. The details depend greatly on communication protocol being used.
If there is not enough bytes to process, you just store them in buffer
*/
bytesReceived += count;
if (MyProtocolMessageComplete(myBuffer, bytesReceived))
{
ProcessMyData(myBuffer, bytesReceived);
AlertOtherThread(); //emit your 'signal' here
bytesReceived = 0; //going to wait for next message
}
}
else
{
//process read() error
}
}
The main idea here is that the thread calling read() is going to be active only when new data arrives. The rest of the time OS will keep this thread in wait state. Thus it will not consume CPU time. It is up to you how to implement the actual signal part.
The example above uses regular read system call to get data from port, but you can use the boost class in the same manner. Just use syncronous read function and the result will be the same.