Qt開發中通過ResetEvent、CreateEvent、SetEvent、WaitForSingleObject實現同步的問題。


以前沒有用過C++的這個事件方式來進行同步的問題,這次嘗試了一下感覺比較好用,在這里分享出來,作者的文件主要以實戰為主,一些概念性的東西會忽略掉,因為這些東西在百度上太多了,這里就不贅述了。

CreateEvent的意思是創建事件。

ResetEvent的意思是指定的事件對象無信號。

SetEvent的意思是設置事件的狀態為有標記,釋放任意等待線程。

WaitForSingleObject的意思是狀態掛起。

簡單的介紹了概念之后我們來看具體的操作。

作者的程序為什么要用到這個東西呢?需要解決什么問題呢?

A模塊的函數中會用到B模塊初始化的變量,A模塊和B模塊都是主界面程序的子類,程序啟動以后A模塊和B模塊很快初始化,在A模塊的定時器中就會馬上用到B模塊初始化的變量,這樣就會有一種情況,B模塊中的變量還沒有初始化完成,A模塊就在使用公用的這個變量,造成野指針以后程序就會崩潰,基於這種情況用到了上面的方式解決。

 

首先在B模塊中創建一個句柄(HANDLE),這里的B模塊其實是一個線程。

HANDLE             m_SortEvent; 

然后在B模塊的構造函數中進行初始化和創建對象。

FireThread::FireThread(QObject *parent)
    : QThread(parent),
    m_SortEvent(INVALID_HANDLE_VALUE)
{
    m_SortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    ResetEvent(m_SortEvent);
}

當然在析構函數中也要做好釋放的工作。

FireThread::~FireThread()
{
    if (INVALID_HANDLE_VALUE != m_SortEvent)
    {
        CloseHandle(m_SortEvent);
    }
}

在線程的run函數會初始化一個Qlist。ResetEvent表示這里已經有信號了,將所有過程運行都完成了setEvent設置無信號,釋放所有等待的線程。同時將QList和句柄通過emit發送出去。

    ResetEvent(m_SortEvent);  

    res = m_SortScanGun0->ConnectScanGun(m_pSettings->GetSortPLC()[SCANGUNADDR0].toString(), m_pSettings->GetSortPLC()[SCANPORT].toInt());
    if (!res)
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_WARN, "Connect to ScanGun0 Device failed!!!");
    }
    else
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_INFO, "Connect to ScanGun0 Device success!!!");
        
    }
    m_ListSorts.append(m_SortScanGun0);

    res = m_SortScanGun1->ConnectScanGun(m_pSettings->GetSortPLC()[SCANGUNADDR1].toString(), m_pSettings->GetSortPLC()[SCANPORT].toInt());
    if (!res)
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_WARN, "Connect to ScanGun1 Device failed!!!");
    }
    else
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_INFO, "Connect to ScanGun1 Device success!!!");
    }
    m_ListSorts.append(m_SortScanGun1);

    res = m_SortScanGun2->ConnectScanGun(m_pSettings->GetSortPLC()[SCANGUNADDR2].toString(), m_pSettings->GetSortPLC()[SCANPORT].toInt());
    if (!res)
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_WARN, "Connect to ScanGun2 Device failed!!!");
    }
    else
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_INFO, "Connect to ScanGun2 Device success!!!");
        
    }
    m_ListSorts.append(m_SortScanGun2);

    res = m_SortScanGun3->ConnectScanGun(m_pSettings->GetSortPLC()[SCANGUNADDR3].toString(), m_pSettings->GetSortPLC()[SCANPORT].toInt());
    if (!res)
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_WARN, "Connect to ScanGun3 Device failed!!!");
    }
    else
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_INFO, "Connect to ScanGun3 Device success!!!");
        
    }
    m_ListSorts.append(m_SortScanGun3);

    res = m_SortScanGun4->ConnectScanGun(m_pSettings->GetSortPLC()[SCANGUNADDR4].toString(), m_pSettings->GetSortPLC()[SCANPORT].toInt());
    if (!res)
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_WARN, "Connect to ScanGun4 Device failed!!!");
    }
    else
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_INFO, "Connect to ScanGun4 Device success!!!");
        
    }
    m_ListSorts.append(m_SortScanGun4);

    res = m_SortScanGun5->ConnectScanGun(m_pSettings->GetSortPLC()[SCANGUNADDR5].toString(), m_pSettings->GetSortPLC()[SCANPORT].toInt());
    if (!res)
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_WARN, "Connect to ScanGun5 Device failed!!!");
    }
    else
    {
        BMSLogger::GetInstance().OutputLog(LogLevel::LOG_INFO, "Connect to ScanGun5 Device success!!!");
        
    }
    m_ListSorts.append(m_SortScanGun5);

    SetEvent(m_SortEvent);
    emit Signal_SendHandle(m_SortEvent);
    emit Signal_SendSortComm(m_ListSorts);

這時在主界面程序中會用到Qt的信號和槽機制

    connect(m_pFireThread, &FireThread::Signal_SendSortComm, m_sortingWidget, &SortingWidget::Slot_GetFireThread, Qt::QueuedConnection);
    connect(m_pFireThread, &FireThread::Signal_SendHandle, m_sortingWidget, &SortingWidget::Slot_GetHandle, Qt::QueuedConnection);

 

void SortingWidget::Slot_GetFireThread(QList<SortCommunication*> tmp_sorts)
{
    m_Sorts = tmp_sorts;
}

void SortingWidget::Slot_GetHandle(HANDLE TmpHandle)
{
    m_TmpSortHandle = TmpHandle;
}

 

這里的m_sortingWidget就相當於前面說到的A模塊。

在A模塊的操作函數中會用到WaitForSingleObject()接口,這個函數有兩個參數,一個是句柄,一個是時間,用在當前的位置表示函數已經掛起,在設置的時間內接收到句柄無信號的時候,掛起等待的線程就釋放了,程序繼續往下走。作者在這里設置的是2000ms。

    int res = WaitForSingleObject(m_TmpSortHandle, 2000);
    int m_grade = 0;
    if (m_Sorts[0]->IsConnected())
    {
        m_Sorts[0]->SendScaninfo();
    }
    TmpTrayCode.clear();
    Sleep(500);

這樣處理以后m_Sort[0]是從QList中取出來的數據,這樣就不會出現因為QList中沒有數據而導致野指針的情況,使程序崩潰了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM