I am using QLocalSocket and QLocalServer for inter process communication on Windows 7 using VS 2010 and Qt 5.5.1.
After sending over 256 messages to the other process the destructor in CIPSocket freezes. I traced the problem to a signal-slot problem in qtbase\src\corelib\ioqwinoverlappedionotifier.cpp where the emitted signal _q_notify() in notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped) does not result in a call of _q_notified(). Therefore the Semaphore hSemaphore exceeds its max-count, resulting in the deadlock in the destructor.
What could be the reason for the signal-slot not working? I could not find any disconnects or block signals.
Thanks in advance.
main.cpp:
#include "main.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <iostream>
int main(int argc, char *argv[])
{
printf("Server (0) or Socket (1)?\n");
char c = getchar();
if (c == '0') {
QCoreApplication app(argc, argv);
CIPServer server;
app.exec();
}
else if (c == '1') {
CIPSocket socket;
for (unsigned int i = 0; i <= 256; ++i) {
socket.update(i);
QThread::msleep(10);
}
}
}
/*--------------------------------------------------------------------------
CIPSocket
----------------------------------------------------------------------------*/
CIPSocket::CIPSocket()
: m_bIsReady(false)
{
m_pSocket = new QLocalSocket(this);
m_stream.setDevice(m_pSocket);
connect(m_pSocket, SIGNAL(connected()), this, SLOT(connectionReady()));
connect(m_pSocket, SIGNAL(disconnected()), this, SLOT(connectionLost()));
m_pSocket->connectToServer("DemoServer");
}
CIPSocket::~CIPSocket()
{
delete m_pSocket;
m_pSocket = NULL;
}
void CIPSocket::update(int i)
{
if (m_bIsReady)
m_stream << i;
}
void CIPSocket::connectionReady()
{ m_bIsReady = true; }
void CIPSocket::connectionLost()
{ m_bIsReady = false; }
/*--------------------------------------------------------------------------
CIPServer
----------------------------------------------------------------------------*/
CIPServer::CIPServer(QObject* parent)
: QLocalServer(parent)
{
if (!listen("DemoServer")) {
throw ("Could not connect to 'DemoServer'");
}
connect(this, SIGNAL(newConnection()), this, SLOT(socketConnected()));
}
CIPServer::~CIPServer()
{}
void CIPServer::socketConnected()
{
qDebug() << "Connected";
m_pConnection = nextPendingConnection();
m_stream.setDevice(m_pConnection);
connect(m_pConnection, SIGNAL(disconnected()), m_pConnection, SLOT(deleteLater()));
connect(m_pConnection, SIGNAL(readyRead()), this, SLOT(update()));
}
void CIPServer::update()
{
if (m_pConnection->bytesAvailable() >= 4) {
int i;
m_stream >> i;
qDebug() << i;
}
}
main.h:
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#include <QtCore/QDataStream>
#include <QtCore/QThread>
/// \brief Creates a socket for inter-process communication
class CIPSocket
: public QObject
{
Q_OBJECT;
public:
/// Constructor
CIPSocket();
/// Destructor
virtual ~CIPSocket();
/// Send the data
void update(int i);
public slots:
/// Enables updating
void connectionReady();
/// Disables updating
void connectionLost();
private:
/// The target stream
QDataStream m_stream;
/// The socket connecting to server
QLocalSocket* m_pSocket;
/// Indicates if the socket is connected
bool m_bIsReady;
};
/// \brief Creates a server for inter-process communication
class CIPServer
: public QLocalServer
{
Q_OBJECT;
public:
/// Constructor
CIPServer(QObject* parent = NULL);
/// Destructor
virtual ~CIPServer();
/// Starts the server
void start();
private slots:
/// Connects the socket to the stream and to the update function
void socketConnected();
/// Reads the data from the stream and emits a the results
void update();
private:
/// The currently connected socket
QLocalSocket* m_pConnection;
/// The incoming stream
QDataStream m_stream;
};
demo.pro:
CONFIG += qt debug
QT += network
HEADERS += main.h
SOURCES += main.cpp
CONFIG += console
The error occurs due to the event loop not running. Starting QCoreApplication starts the event loop, but waits for the application to quit. Therefore the sending has to be done in another thread. Attached code shows the correct usage.
main.cpp:
#include "main.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
printf("Server (0) or Socket (1)?\n");
char c = getchar();
if (c == '0') {
CIPServer server;
QCoreApplication::exec();
}
else if (c == '1') {
CIPSocket socket;
CSender sender(500);
QObject::connect(&sender, SIGNAL(sendMessage(int)), &socket, SLOT(update(int)));
QObject::connect(&sender, SIGNAL(allMessagesSent()), &socket, SLOT(close()));
sender.start();
QCoreApplication::exec();
}
}
/*--------------------------------------------------------------------------
CIPSocket
----------------------------------------------------------------------------*/
CIPSocket::CIPSocket()
: m_bIsReady(false)
{
m_pSocket = new QLocalSocket(this);
m_stream.setDevice(m_pSocket);
connect(m_pSocket, SIGNAL(connected()), this, SLOT(connectionReady()));
connect(m_pSocket, SIGNAL(disconnected()), this, SLOT(connectionLost()));
m_pSocket->connectToServer("DemoServer");
}
CIPSocket::~CIPSocket()
{
delete m_pSocket;
m_pSocket = NULL;
}
void CIPSocket::update(int i)
{
if (m_bIsReady)
m_stream << i;
}
void CIPSocket::connectionReady()
{ m_bIsReady = true; }
void CIPSocket::connectionLost()
{ m_bIsReady = false; }
void CIPSocket::close()
{ QCoreApplication::exit(); }
/*--------------------------------------------------------------------------
CIPServer
----------------------------------------------------------------------------*/
CIPServer::CIPServer(QObject* parent)
: QLocalServer(parent)
{
if (!listen("DemoServer")) {
throw ("Could not connect to 'DemoServer'");
}
connect(this, SIGNAL(newConnection()), this, SLOT(socketConnected()));
}
CIPServer::~CIPServer()
{}
void CIPServer::socketConnected()
{
qDebug() << "Connected";
m_pConnection = nextPendingConnection();
m_stream.setDevice(m_pConnection);
connect(m_pConnection, SIGNAL(disconnected()), m_pConnection, SLOT(deleteLater()));
connect(m_pConnection, SIGNAL(readyRead()), this, SLOT(update()));
connect(m_pConnection, SIGNAL(disconnected()), this, SLOT(close()));
}
void CIPServer::update()
{
if (m_pConnection->bytesAvailable() >= 4) {
int i;
m_stream >> i;
qDebug() << i;
}
}
void CIPServer::close()
{ QCoreApplication::exit(); }
/*--------------------------------------------------------------------------
CSender
----------------------------------------------------------------------------*/
CSender::CSender(int iNumMessages)
: m_iNumMessages(iNumMessages)
{}
CSender::~CSender()
{}
void CSender::run()
{
while (m_iNumMessages > 0) {
emit sendMessage(m_iNumMessages);
msleep(10);
m_iNumMessages--;
}
emit allMessagesSent();
}
main.h:
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#include <QtCore/QDataStream>
#include <QtCore/QThread>
#include <QtCore/QCoreApplication>
/// \brief Creates a socket for inter-process communication
class CIPSocket
: public QObject
{
Q_OBJECT;
public:
/// Constructor
CIPSocket();
/// Destructor
virtual ~CIPSocket();
public slots:
/// Enables updating
void connectionReady();
/// Disables updating
void connectionLost();
/// Send the data
void update(int i);
/// Close the application
void close();
private:
/// The target stream
QDataStream m_stream;
/// The socket connecting to server
QLocalSocket* m_pSocket;
/// Indicates if the socket is connected
bool m_bIsReady;
};
/// \brief Creates a server for inter-process communication
class CIPServer
: public QLocalServer
{
Q_OBJECT;
public:
/// Constructor
CIPServer(QObject* parent = NULL);
/// Destructor
virtual ~CIPServer();
private slots:
/// Connects the socket to the stream and to the update function
void socketConnected();
/// Reads the data from the stream and emits a the results
void update();
/// Close the application
void close();
private:
/// The currently connected socket
QLocalSocket* m_pConnection;
/// The incoming stream
QDataStream m_stream;
};
/// \brief Sends the messages via CIPSocket
class CSender
: public QThread
{
Q_OBJECT;
public:
/// Constructor
CSender(int iNumMessages);
/// Destructor
virtual ~CSender();
/// Sends the requestet number of messages in 10 ms steps
virtual void run();
signals:
/// Sends the message via the CIPSocket
void sendMessage(int);
/// Informs about all messages being sent
void allMessagesSent();
private:
/// The number of messages to send
int m_iNumMessages;
};