Dear Experts,

I am working on an application which will exchange the data between the Qt thread and the windows console application. I am developing these applications using MS VS 2008 with Qt plugin in Windows platform.

The design is as follows:

  • Windows "NamedPipe" is used as IPC for exchaning the data between two applications.
  • AplicationA
    • Main GUI application designed using Qt and it has two dedicated QThreads for read and write operations on NamedPipe.
    • Creates Windows "NamedPipe" in on startup using
      Qt Code:
      1. m_shPipeHandle = CreateNamedPipe(
      2. lpszPipename, // pipe name
      3. PIPE_ACCESS_DUPLEX, // read/write access
      4. PIPE_TYPE_MESSAGE | // message type pipe
      5. PIPE_READMODE_MESSAGE | // message-read mode
      6. PIPE_WAIT, // blocking mode
      7. PIPE_UNLIMITED_INSTANCES, // max. instances
      8. BUFFER_SIZE, // output buffer size
      9. BUFFER_SIZE, // input buffer size
      10. NMPWAIT_USE_DEFAULT_WAIT, // client time-out
      11. NULL); // default security attribute
      To copy to clipboard, switch view to plain text mode 
    • Launches "ApplicationB" using
      Qt Code:
      1. QProcess::startDetached("ApplicationB.exe");
      To copy to clipboard, switch view to plain text mode 
    • Starts two Qt Threads (one for read operation and another for write operation) using
      Qt Code:
      1. m_pReaderThread = new QThread;
      2. m_pReader = new CWorker();
      3. m_pWriterThread = new QThread;
      4. m_pWriter = new CWorker();
      5.  
      6. m_pReader->moveToThread(m_pReaderThread);
      7. m_pWriter->moveToThread(m_pWriterThread);
      8.  
      9. connect(m_pReaderThread, SIGNAL(started()), m_pReader, SLOT(doReadData()));
      10. connect(m_pReader, SIGNAL(finishedWork()), m_pReaderThread, SLOT(quit()));
      11. connect(m_pReader, SIGNAL(finishedWork()), m_pReader, SLOT(deleteLater()));
      12. connect(m_pReaderThread, SIGNAL(finished()), m_pReaderThread, SLOT(deleteLater()));
      13.  
      14. connect(m_pWriterThread, SIGNAL(started()), m_pWriter, SLOT(doWriteData()));
      15. connect(m_pWriter, SIGNAL(finishedWork()), m_pWriterThread, SLOT(quit()));
      16. connect(m_pWriter, SIGNAL(finishedWork()), m_pWriter, SLOT(deleteLater()));
      17. connect(m_pWriterThread, SIGNAL(finished()), m_pWriterThread, SLOT(deleteLater()));
      18.  
      19. connect(m_pSampleUi->btnStartStop, SIGNAL(clicked()), this, SLOT(sltToggleButton()));
      20.  
      21. m_pReaderThread->start();
      22. m_pWriterThread->start();
      To copy to clipboard, switch view to plain text mode 

      The `CWorker::doReadData()` looks as follows:
      Qt Code:
      1. void CWorker::doReadData()
      2. {
      3. char szBuffer[BUFFER_SIZE];
      4. DWORD cbBytes;
      5. bool bResult = false;
      6.  
      7. ConnectNamedPipe(CWorker::m_shPipeHandle, NULL);
      8.  
      9. do {
      10. //Read client message
      11. bResult = ReadFile(
      12. m_shPipeHandle, // handle to pipe
      13. szBuffer, // buffer to receive data
      14. BUFFER_SIZE, // size of buffer
      15. &cbBytes, // number of bytes read
      16. NULL); // not overlapped I/O
      17.  
      18. if ((!bResult) || (!cbBytes))
      19. {
      20. qDebug()<<"\nError occurred while reading from the client:"<<GetLastError();
      21. // TODO: Action to be taken on failure
      22. }
      23. else
      24. {
      25. qDebug()<<"Client sent following message:"<<szBuffer;
      26. // Inform the Main UI thread to update UI elements or to do necessary action.
      27. emit dataAvailable(QString(szBuffer).toInt());
      28.  
      29. // Update the shared m_enumCmd so that Writer thread can write the Acknowledgement in NamedPipe so that "ApplicationB" can read & process it.
      30. m_Mutex.lock();
      31. m_enumCmd = COMMAND_ACK_READ;
      32. m_Mutex.unlock();
      33.  
      34. // Release the semaphore so that writer thread can acquire and starts writing the data (ACK) onto the pipe.
      35. m_Sem.release();
      36. }
      37. } while(m_bReadThreadControl);
      38. }
      To copy to clipboard, switch view to plain text mode 

      The `CWorker::doWriteData()` looks as follows:
      Qt Code:
      1. void CWorker::doWriteData()
      2. {
      3. DWORD cbBytes;
      4. bool bResult = false;
      5. char szBuffer[BUFFER_SIZE];
      6.  
      7. do
      8. {
      9. m_Sem.acquire();
      10.  
      11. qDebug()<<"\nInside the Write Loop\n";
      12.  
      13. switch(m_enumCmd)
      14. {
      15. case COMMAND_PAUSE_SERVICE:
      16. sprintf(szBuffer, "%d", COMMAND_PAUSE_SERVICE);
      17. break;
      18. case COMMAND_RESUME_SERVICE:
      19. sprintf(szBuffer, "%d", COMMAND_RESUME_SERVICE);
      20. break;
      21. case COMMAND_ACK_READ:
      22. sprintf(szBuffer, "%d", COMMAND_ACK_READ);
      23. break;
      24. case COMMAND_UNKNOWN:
      25. default:
      26. szBuffer[0] = '\0';
      27. break;
      28. }
      29.  
      30. bResult = WriteFile(
      31. m_shPipeHandle, // handle to pipe
      32. szBuffer, // buffer to write from
      33. strlen(szBuffer) + 1, // number of bytes to write, include the NULL
      34. &cbBytes, // number of bytes written
      35. NULL);
      36.  
      37. if ((!bResult) || (!cbBytes))
      38. {
      39. qDebug()<<"\nError occurred while writing to the client:"<<GetLastError();
      40. // TODO: Action to be taken on failure
      41. }
      42. else
      43. {
      44. qDebug()<<"Written data is: "<<szBuffer;
      45. }
      46.  
      47. } while (m_bWriteThreadControl);
      48. }
      To copy to clipboard, switch view to plain text mode 






  • ApplicationB
    • Its normal windows console application.
    • Connects to the named pipe using
      Qt Code:
      1. //Connect to the server pipe using CreateFile()
      2. hPipe = CreateFile(
      3. lpszPipename, // pipe name
      4. GENERIC_READ | GENERIC_WRITE, // read and write access
      5. 0, // no sharing
      6. NULL, // default security attributes
      7. OPEN_EXISTING, // opens existing pipe
      8. FILE_ATTRIBUTE_NORMAL, // default attributes
      9. NULL); // no template file
      To copy to clipboard, switch view to plain text mode 
    • Waits for input from user and writes the user data to the Pipe and then it waits for the acknowledgement from the server.
      Qt Code:
      1. while (1)
      2. {
      3. // Reset the buffer
      4. szBuffer[0] = 0;
      5.  
      6. // Wait for the user input and update msgId;
      7.  
      8. // Store the msg id value to the szBuffer.
      9. sprintf(szBuffer, "%d", msgId);
      10. szBuffer[strlen(szBuffer)] = 0;
      11.  
      12. //Send the message to server
      13. BOOL bResult = WriteFile(
      14. hPipe, // handle to pipe
      15. szBuffer, // buffer to write from
      16. strlen(szBuffer) + 1, // number of bytes to write, include the NULL
      17. &cbBytes, // number of bytes written
      18. NULL); // not overlapped I/O
      19.  
      20. if ((!bResult) || (!cbBytes))
      21. {
      22. std::cout<<"\nError occurred while writing to the server:"<<GetLastError();
      23. }
      24. else
      25. {
      26. std::cout<<"\nWriteFile() was successful.";
      27. std::cout<<"\nWritten"<<szBuffer<<"to the Pipe\n";
      28. }
      29.  
      30. //Read server response
      31. bResult = ReadFile(
      32. hPipe, // handle to pipe
      33. szBuffer, // buffer to receive data
      34. BUFFER_SIZE,
      35. &cbBytes, // number of bytes read
      36. NULL); // not overlapped I/O
      37.  
      38. if ((!bResult) )//|| (0 == cbBytes))
      39. {
      40. std::cout<<"\nError occurred while reading from the server:"<<GetLastError();
      41. }
      42. else
      43. {
      44. std::cout<<"\nReadFile() was successful.";
      45. std::cout<<"\nServer sent the following message:"<<szBuffer<<std::endl;
      46. }
      47. }
      To copy to clipboard, switch view to plain text mode 

Questions:
My intention is to dedicate a thread exclusively for Read operation and another thread exclusively for Write operation. Even if the ReadThread wants to send any data (say acknowledgement) it should intimate the WriterThread (by releasing semaphore).
  • a. Is there anything wrong in the way I am trying to synchronize the read and write operations at the Qt Application side.
  • b. Will there be any problem If we try to synchronze the operations between the the QProcess (Console App) and the QThreads?
  • c. How do I synchronize the read/write operations without any delay between Qt Application and Console Application.
  • d. Can you please suggest the better way to achieve this functionality