PDA

View Full Version : Wait for thread to complete before reading data?



TheVirus
26th April 2011, 03:58
I'm using a thread to read input from a socket (the reasoning for the thread is when I use socket->waitForReadyRead(-1), it pauses my entire program and prevents another socket from accepting/sending data, which causes it to wait forever). I want to set data with that thread, so I used a SIGNAL/SLOT. The question I have, how can I make sure the data is set before reading from it? I'm looking at mutex locks, but I'm unsure of how to do it.

Here's a basic idea of what I'm doing:



QList<QByteArray> myList;
QReadWriteLock lock;

QList<QByteArray> MainWindow::getData(QString cmd) {
thread = new MyThread(cmd);
thread->start();
connect(thread, SIGNAL(dataReady(QList<QByteArray>), this, SLOT(readThreadData(QList<QByteArray>)));
//Lock myList?
return myList;
}

void MainWindow::readThreadData(QList<QByteArray> tList) {
myList = tList;
//Unlock myList?
}

void MainWindow::loadDataFromList(QString cmd) {
getData(cmd);
//Read from myList?
}


I'm not sure if this is the right approach but I'm not sure how to proceed. I'm sending a command to a program and I wait for input on a socket. The problem is, the program responds to another socket first and then responds to my request.

SockA -> Program
Program -> SockB
SockB -> SOMEWANSOCKET
SOMEWANSOCKET -> SockB
SockB -> Program
Program -> SockA

SockA/SockB are internal to my software. Program is an application I'm communicating with and SOMEWANSOCKET is some server software over the WAN I am communicating with.

What I'm getting is:

SockA -> Program
Program -> SockB
... Can't do anything because SockA is in an infinite loop waiting for readyRead().

I never noticed this before because I was doing everything via localhost and noticed it when I introduced the WAN. I hope that makes sense, it does in my head... :crying:

Added after 49 minutes:

Just a side note. The way I had it before, I didn't use threads. I simply created an object from another class that handled the input/output of the socket.



runCommand = new CommandRunner();
arrayList = runCommand->doRun(cmd);
return arrayList;


So, if I can do this without needing threads, that's fine with me, but I think I'll have to since I have to make sure I receive all the data before trying to parse it. If I lower my waitForReadyRead() times, it still fails as the function returns before the data is finished being sent.

TheVirus
26th April 2011, 15:45
After getting some sleep, I've written a more thorough description of my problem and how I am working with the sockets. This is all pseudo code.



SockA -> connect to local service.
SockB -> listen for connection. (localhost:9999)
SockC -> connect to remote service.
SockA -> send 'START on localhost:9999'
LSERVICE -> SockA 'OK'
LSERVICE -> connect to SockB
LSERVICE -> SockB 'INIT'
SockB -> SockC 'LIST'
SockC -> SockB '1234'
SockB -> LSERVICE '1234' (looks up what 1234 is)
LSERVICE -> SockA 'John'
LSERVICE -> SockA 'Q' (could be completely ignored and go straight to the next line)
LSERVICE -> SockA 'Public'
... more commands


I have the following setup:

lsServer QTcpServer (opens port 9999 on localhost)
rsServer QTcpSocket (connects to a remote service)
cmdRunnr QTcpSocket (connects to local service to issue commands)

I need to communicate between the 3 sockets in varying ways. I do not have control of the 'local service' program. lsServer and rsServer are non-threaded classes that read and write to each other's sockets.

For example:


connect(rsServer, SIGNAL(readyRead()), this, SLOT(readFromRemote()));

readFromRemote() {
QByteArray input;
input = rsServer->read(4096);
lsServer->write(input);
}


rsServer passes data that it receives to lsServer.

I use cmdRunnr to connect to a local service and use my program as a proxy of sorts to issue commands to a remote host that I'm directly connected to. The problem is, I need a way to wait until a variable is valid before continuing and I need a way to wait for input to return to the socket before continuing.

For example:


getValidList() {
QString cmd = "LIST";
QList<QByteArray> myList;

myList = getListFromRemote(cmd);
//... do stuff with myList ...
}

getListFromRemote(QString cmd) {
cmdRunnr = new CommandRunner(cmd);
cmdRunnr->start();
//... Find a way to get cmdRunnr->runnerList (QList<QByteArray>) ...
return runnerList;
}

in CommandRunner:

CommandRunner::CommandRunner(QObject *parent, QString cmd) : QThread { //constructor
runnerCmd = cmd;
}

CommandRunner:run() {
QByteArray input;
mySocket = new QTcpSocket();
mySocket.connectToHost(localhost, 4351);

//... do I connect()? ...
mySocket->write(runnerCmd);
mySocket->waitForReadyRead(5000);
input = mySocket->read(4096);
//... input should be OK ...
mySocket->waitForReadyRead(5000);
input = mySocket->read(4096);
//... input might be 'John' followed by more information or simply end at that ...
}

The only way I know the data is finished is when the socket disconnects. There are headers I can read to determine if it's DATA or REPLY. I'm in a conundrum and am unsure of how to tackle this problem.