使用套接字时防止死锁

时间:2014-11-09 22:02:41

标签: c++ qt sockets

我是第一次在C ++上使用服务器(我使用qt作为G.U.I.框架)/客户端应用程序,我偶然发现了一个相当烦人的问题。

首先,让我提供一些细节:

I am on Windows 10 x64 i'm using Visual Studio as my IDE & QT for the G.U.I.
all signal/slots are used as needed are connected.
I am new to multi-threading concepts.
I am self-taught, so I don't know that much about what certain concepts are called.

基本大纲:

I am currently working on the file uploader.
For the file uploader, I have two classes, one is for the thread which communicates with the client(let's call it classA) & the other is the QObject for the form(let's call it classB).


When the user closes the form 
it triggers closeEvent() in classB which sets the 'bDead' variable in classA(it uses the QMutex to make sure the other thread isn't accessing it, so I suppose it's thread-safe).
Once the client thread notices the change in classA, it finishes up it's work & sets bVerifiedDead in classB to true so they can both free themselves without worry of being accessed when destroyed.

表单:

#include "uploadselect.h"

UploadSelect::UploadSelect(QWidget *parent) :
QWidget(parent)
{
    ui.setupUi(this);
    bClosedByUser = true;
    bVerifiedDead = false;
    bDead = NULL;
}

/*
bool UploadSelect::VerifyDeath()
{
    bool bResult;
    mutex.lock();
    bResult = bVerifiedDead;
    mutex.unlock();
    return bResult;
}
*/

void UploadSelect::Close()
{
    bClosedByUser = false;
    close();
}

void UploadSelect::closeEvent(QCloseEvent *event)
{
    if (bClosedByUser)
    {
        mutex.lock();
        *bDead = true;
        mutex.unlock();
        while (true)
        {
            mutex.lock();
            if (bVerifiedDead)
            {
                mutex.unlock();
                break;
            }
            mutex.unlock();
            Sleep(250);
        }
    }
    delete this;
}

uploadselect.h:

#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <WinSock2.h>
#include <Windows.h>

#include <QWidget>
#include <QDialog>
#include "ui_uploadselect.h"

class UploadSelect : public QWidget
{
    Q_OBJECT
public:
    UploadSelect(QWidget *parent = 0);
    ~UploadSelect(){};
    QMutex mutex;
    bool bClosedByUser, *bDead, bVerifiedDead;
    public slots:
    void Close();
private:
    Ui::UploadSelect ui;
protected:
    void closeEvent(QCloseEvent *event);
};

uploadselectthrd.h:

#pragma once
#include <QThread>
#include <qsystemtrayicon.h>
#include <qtreewidget.h>

class UploadSelect;
class UploaderSelectThread : public QThread{
    Q_OBJECT
public:
    UploaderSelectThread(QObject* parent = 0){ bFormDead = false; };
    ~UploaderSelectThread(){};
    void run();
    bool bFormDead;
    UploadSelect* UI;
private:
    bool FormDying();
signals:
    void Close();
};

uploadselectthrd.cpp:

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX //error C2589: '(' : illegal token on right side of '::'   c:\qt\5.3\msvc2013_64\include\qtcore\qdatetime.h will occur if this is not defined before windows.h/winsock2.h(winsock2 most likely includes windows.h)
#define NOMINMAX 
#endif
#include <WinSock2.h>
#include <Windows.h>

#include <qmutex.h>
#include "FileList.h"

#include "uploadselecthrd.h"
#include "uploadselect.h"
#include "../stub/sockutils.h"

using namespace SockWrapper;


bool UploaderSelectThread::FormDying()
{
    bool bResult;
    UI->mutex.lock();
    bResult = bFormDead;
    UI->mutex.unlock();
    return bResult;
}


void UploaderSelectThread::run()
{
    connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));

    //SocketWrapper* Client = new SocketWrapper(sSock);
    int i = 0;
    while (i < 6 && FormDying() == false)
    {
        Sleep(1000);
        i++;
    }

    if (!FormDying())
    {
        OutputDebugStringA("\r\n\r\n\r\n\r\nbFormDead == false");
        emit Close();
    }
    else
    {
        UI->mutex.lock();
        UI->bVerifiedDead = true;
        UI->mutex.unlock();
        OutputDebugStringA("\r\n\r\n\r\n\r\nbFormDead == true");
    }

}

我编码的方式;套接字是同步的,所以让我们假设客户端的连接不是很好,并且在send函数返回之前大约需要10秒,并允许客户端检查变量。

这会造成10秒的死锁,这很糟糕......

它不完整,因为上一个项目搞砸了(所以我开了一个新的,我慢慢地将所有内容重新编码)。

我想到的可能的解决方案:

instead of deleting the classB in closeEvent(), simply set a variable in classA in which the thread for classA will take care of it when it's finished.

0 个答案:

没有答案