簡體   English   中英

WaitforSingleObject錯過了信號事件

[英]WaitforSingleObject missed a signal event

我檢查了相關帖子,但仍然無法找到答案。 專家,請幫助我。 我基本上有兩個線程,一個線程從以太網接收數據,另一個線程處理接收到的數據。 為了獲得最佳性能,請在第ThreadRecv接收第n幀和第ThreadCompute Process(n-1)的幀。 我記錄了時序關系,發現如果事件在等待功能之前發出信號,它將不會得到該事件。

這是粗糙的代碼:

st_threads::st_threads():Event_ComputeDone(0,0),Sem_KillThread(0,2),
        Sem_PauseThread(0,2),Sem_ResumeThread(0,2),Event_RecvDone(0,0),
        Event_RecvTerminated(0,0),Event_RecvPaused(0,0),Event_RecvStart(0,0),//make it automatic
        Event_ComputeTerminated(0,0),Event_ComputePaused(0,0)
{
    ping_num=0;
    thread_state=stopped;
    step=1;
    //threadHandles[0]=0;
    //threadHandles[1]=0;
}

UINT st_threads::ThreadRecv(LPVOID pParam)
{
    st_threads *pThread=(st_threads*)pParam; //get the pointer
    hptime t0;
    double dtime,dtime0;
    while(1)
    {
        dtime0=t0.gettime();
        //check if terminate the thread

        if(pThread->ping_num)
        WaitForSingleObject(pThread->Event_RecvStart,INFINITE);


        //realtime processing
        dtime=t0.gettime();
        switch(pThread->work_mode)
        {
        case realtime_mode:
            //if(pThread->ECP->IsAlive())
            {
                pThread->frame_len=pThread->ECP->RecvDataFrame(pThread->rawbuf,MAX_RAW_BUF_SIZE); //receive a data frame into a buffer
                if(pThread->frame_len<192)
                {
                    pThread->frame_len=pThread->ECP->RecvDataFrame(pThread->rawbuf,MAX_RAW_BUF_SIZE); //receive a data frame into a buffer
                }
                if(pThread->frame_len<0)
                {
                    TRACE("recv error\n");
                }
                pThread->pdatalist->push_back(raw_data(pThread->frame_len,pThread->rawbuf,pThread->ping_num));
                pThread->praw_frame[pThread->ping_num%2]=--pThread->pdatalist->raw_buf.end();
            }
            break;

        default:break;
        }

        pThread->ping_num++;
        pThread->Event_RecvDone.SetEvent(); //let compute to start

        pThread->threadtime.time_ThreadRecv=dtime0;
        pThread->threadtime.dt_recv=t0.gettime()-dtime;
        pThread->threadtime.dt_ThreadRecv=t0.gettime()-pThread->threadtime.time_ThreadRecv;
        //
        //TRACE("RECV:ping#=%d\n",pThread->ping_num);

    }

    AfxEndThread(0);
    return 0;
}

UINT st_threads::ThreadCompute(LPVOID pParam)
{
    st_threads *pThread=(st_threads*)pParam;

    int prev_frame_time=0,data_mode;
    double time_elapsed,dt,dtime0;
    hptime t0;
    while(1)
    {
        //WaitForSingleObject(pThread->Event_ComputeStart,INFINITE);
        dtime0=t0.gettime();

        WaitForSingleObject(pThread->Event_RecvDone,INFINITE);
        pThread->Event_RecvStart.SetEvent(); //let recv start at the same time as computing


        //realtime processing
        if(pThread->ping_num)
        {
            dt=t0.gettime();
            pThread->dispatch_packet(pThread->praw_frame[(pThread->ping_num-1)%2],&data_mode,pThread->ping_num-1);
            pThread->threadtime.dt_comp=t0.gettime()-dt;

                pThread->threadtime.dt_frame_interval=t0.gettime()-dtime0;

        }
        //else Sleep(100);
        pThread->Event_ComputeDone.SetEvent();

        pThread->threadtime.time_ThreadCompute=dtime0;
        pThread->threadtime.dt_ThreadCompute=dt=t0.gettime()-pThread->threadtime.time_ThreadCompute;
        if(pThread->debug_mode) pThread->logtime(pThread->ping_num,data_mode);
        //TRACE("COMP:ping#=%d, frame rate: %d\n",pThread->ping_num,int(1000.0/dt));
        //
    }
    AfxEndThread(0);
    return 0;
}

該程序將記錄時間,部分輸出將如下所示:

0177 15 364486101   23  23  364486099   23  21  23
0178 15 364486124   23  23  364486122   23  21  23
0179 15 364486147   23  23  364486145   23  20  23
0180 15 364486170   23  23  364486167   23  21  23
0181 15 364486193   23  23  364486190   23  21  23
0182 15 364486216   21  21  364486213   23  20  21
0183 15 364486238   23  23  364486236   23  21  23
0184 15 364486261   23  23  364486259   23  21  23
0185 15 364486284   22  22  364486282   23  21  22
0186 15 364486307   23  23  364486305   23  21  23
0187 15 364486330   23  23  364486328   23  21  23
0188 15 364486353   23  23  364486351   23  20  23
0189 15 364486376   23  22  364486374   23  20  23
0190 15 364486399   23  23  364486396   23  21  23
0191 15 364486422   23  23  364486420   23  21  23
0192 15 364486445   23  23  364486442   23  21  23
0193 15 364486468   23  23  364486465   23  20  23
0194 15 364486491   22  22  364486488   23  20  22
0195 15 364486513   23  23  364486511   23  21  23
0196 15 364486536   23  23  364486534   23  21  23
0197 15 364486559   22  22  364486557   23  21  22
0198 15 364486582   23  23  364486580   23  21  23
0199 15 364486605   23  23  364486603   23  20  23
0200 15 364486628   23  23  364486625   25  23  23
0200 15 364486651   23  23  364486625   25  23  23
0201 15 364486674   24  22  364486650   26  25  24
0202 15 364486698   25  22  364486676   25  25  25
0203 15 364486723   26  23  364486701   25  25  26
0204 15 364486749   25  23  364486726   25  25  25
0205 15 364486774   24  22  364486751   25  25  24
0206 15 364486798   26  22  364486776   26  26  26
0207 15 364486825   24  21  364486802   25  25  24
0208 15 364486849   25  22  364486827   25  25  25
0209 15 364486874   25  22  364486852   25  25  25
0210 15 364486900   25  22  364486877   25  25  25
0211 15 364486925   25  22  364486902   26  25  25
0212 15 364486950   25  22  364486928   25  25  25
0213 15 364486975   26  22  364486953   26  26  26
0214 15 364487001   26  22  364486979   26  26  26
0215 15 364487027   24  22  364487004   25  25  24
0216 15 364487051   25  22  364487029   25  25  25
0217 15 364487076   29  22  364487054   29  29  29
0218 15 364487106   26  23  364487083   26  26  26
0219 15 364487132   25  22  364487109   26  26  25

第一列是ping編號,第二列是不相關的,第三列是ThreadCompute的絕對時間,第四列是ThreadCompute的持續時間,第五列是不釋放的,第六列是ThreadRecv,第七列是threadRecv的持續時間。 請注意,我們得到了兩個相同的輸出,其ping號為200。這表明threadrecv比ThreadCompute慢一點。 recvStart的發布要早於Wait函數,並且不會收到它。

這是完全錯誤的設計。

 WaitForSingleObject(pThread->Event_RecvDone,INFINITE);
 pThread->Event_RecvStart.SetEvent(); //let recv start at the same time as computing

您等待接收到一個數據包(由ping_num標識),並告訴Receiver線程繼續接收, 然后開始處理該數據包。 在計算線程完成對剛剛接收到的數據包的處理之前 ,接收方線程可能會增加ping_num。 在多線程環境中,這是完全可能的。

我認為您應該重新設計接收/計算過程的邏輯。 最好使用列表或隊列將接收到的數據包存儲在Receiver線程中,並將其提取到Computing線程中。 當然,您必須使用Mutex或其他方式來保護列表/隊列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM