Qt - QLocalSocket信号槽不工作导致析构函数死锁

Qt - QLocalSocket Signal-Slot not working resulting in deadlocks in destructor

本文关键字:析构函数 死锁 工作 QLocalSocket 信号 Qt      更新时间:2023-10-16

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

发送超过256条消息到另一个进程后,CIPSocket中的析构函数冻结。我将问题跟踪到qtbasesrccorelibioqwinoverlappedionotifier.cpp中的信号槽问题,其中在notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED * OVERLAPPED)中发出的信号_q_notify()不会导致调用_q_notified()。因此,信号量hSemaphore超过了它的max-count,导致析构函数中的死锁。

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

提前感谢。

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

由于事件循环未运行而发生错误。启动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;
    };

程序运行良好,如它被编程:尝试以下:

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

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

app.exec();

问题是:它应该做什么?

我猜你喜欢下班后退出程序,那么插入:

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

试试这些动作:启动服务器-启动客户端,发送数据-服务器接收数据-停止客户端-服务器也停止