Qt - QLocalSocket Signal-Slot不工作导致析构函数死锁

时间:2016-07-05 10:10:05

标签: c++ qt networking signals-slots

我正在使用QLocalSocket和QLocalServer在Windows 7上使用VS 2010和Qt 5.5.1进行进程间通信。

向另一个进程发送超过256条消息后,CIPSocket中的析构函数冻结。我将问题追溯到qtbase \ src \ corelib \ ioqwinoverlappedionotifier.cpp中的信号槽问题,其中通知中发出的信号_q_notify()(DWORD numberOfBytes,DWORD errorCode,OVERLAPPED *重叠)不会导致调用_q_notified() 。因此,信号量hSemaphore超出其最大计数,导致析构函数死锁。

信号槽无法正常工作的原因是什么?我找不到任何断开连接或阻塞信号。

提前致谢。

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

2 个答案:

答案 0 :(得分:1)

由于事件循环未运行而发生错误。启动QCoreApplication启动事件循环,但等待应用程序退出。因此,发送必须在另一个线程中完成。 附加的代码显示正确的用法。

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;
    };

答案 1 :(得分:0)

该程序在编程时运行良好:尝试以下方法:

启动服务器 - 启动客户端,发送数据 - 服务器接收数据 - 停止客户端 - 再次启动客户端,发送数据 - 服务器接收数据......

该程序没有死锁,也没有冻结!该程序正在等待第13行的Qt eventloop中的事件:

app.exec();

问题是:它该怎么办?

我假设你想在下班后退出程序,然后插入:

void CIPServer::socketConnected()
{ . . .
  connect(m_pConnection, SIGNAL(disconnected()), this, SLOT(theend()));
}
void CIPServer::theend()
{
    QCoreApplication::quit();
}

尝试以下操作: 启动服务器 - 启动客户端,发送数据 - 服务器接收数据 - 停止客户端 - 服务器也停止