2012-06-14 63 views
1

這些天,我想了解更多有關線程在Windows中的東西。我想到了這個實際應用:C++ winapi線程

假設按下按鈕「開始」時有多個線程啓動。假設這些線程是密集的(他們繼續運行/總是有一些工作)。

這個程序也會有一個「停止」按鈕。當按下這個按鈕時,所有的線程都會以一種很好的方式關閉:釋放資源並放棄工作並返回按下「開始」按鈕之前的狀態。

該應用程序的另一個要求是,如果按下「停止」按鈕,線程運行的函數不應包含任何指令檢查。線程中運行的函數不應該關心停止按鈕。

語言:C++

操作系統:Windows

問題:

WrapperFunc(function, param)  
{ 
    // what to write here ? 
    // if i write this: 
    function(param); 
    // i cannot stop the function from executing 
} 
  • 我應該如何構建包裝函數,這樣我可以正確地停止線程? (不使用TerminateThread或其他功能)

  • 如果程序員動態地分配一些內存會怎麼樣?我怎麼才能在關閉 線程之前釋放它?(注意,當我按下「停止按鈕」時,線程仍在處理數據) 我雖然關於重載新操作符或只是強加使用預定義的 函數來使用動態分配內存。但是,這意味着 使用此API的程序員受到限制,而這不是我想要的。

謝謝

編輯:骷髏來形容,我想實現的功能。

struct wrapper_data 
{ 
     void* (*function)(LPVOID); 
     LPVOID *params; 
}; 

/* 
this function should make sure that the threads stop properly 
(free memory allocated dynamically etc) 
*/ 
void* WrapperFunc(LPVOID *arg)  
{ 
    wrapper_data *data = (wrapper_data*) arg; 
    // what to write here ? 
    // if i write this: 
    data->function(data->params); 
    // i cannot stop the function from executing 
    delete data; 
} 

// will have exactly the same arguments as CreateThread 
MyCreateThread(..., function, params, ...) 
{ 
    // this should create a thread that runs the wrapper function 
    wrapper_data *data = new wrapper_data; 
    data->function = function; 
    data->params = params; 

    CreateThread(..., WrapperFunc, (LPVOID) wrapper_data, ...); 
} 

thread_function(LPVOID *data) 
{ 
    while(1) 
    { 
     //do stuff 
    } 
} 

// as you can see I want it to be completely invisible 
// to the programmer who uses this 
MyCreateThread(..., thread_function, (LPVOID) params,...); 

回答

0

一種解決方案是讓某種信號告訴線程停止工作。通常這可以是一個全局布爾變量,通常是false,但當設置爲true時,它會告訴線程停止。至於清理,在從線程返回之前完成線程主循環時執行它。

I.e.是這樣的:

volatile bool gStopThreads = false; // Defaults to false, threads should not stop 

void thread_function() 
{ 
    while (!gStopThreads) 
    { 
     // Do some stuff 
    } 

    // All processing done, clean up after my self here 
} 

至於清理一下,如果你保持一個結構或一個類裏面的數據,就可以強行線程外殺他們,只是要麼delete的,如果你實例動態分配它們或讓系統處理它,如果創建,例如在堆棧上或作爲全局對象。當然,線程分配的所有數據(包括文件,套接字等)必須放置在這個結構或類中。


保持停止功能,在包裝的一種方式,是在包裝的實際主循環,隨用隨取的停止信號一起。然後在主循環中調用一個類似doStuff的函數來處理實際的處理。但是,如果它包含可能需要時間的操作,則會再次遇到第一個問題。

+2

考慮使用'volatile'關鍵字來防止編譯器導致布爾值被緩存並保存在一個寄存器中,從而防止線程中的值發生變化。 – 2012-06-14 10:26:50

+0

問題是我想讓用戶不關心在線程函數中停止,只需編寫功能。 –

+0

@infact好主意,完成。 –

0

見我回答這個類似的問題:

How do I guarantee fast shutdown of my win32 app?

基本上,你可以使用函數QueueUserAPC排隊會拋出異常的PROC。這個異常應該在你的線程過程中一直冒泡到'catch'。

只要您使用的任何庫都具有相當的異常感知能力並使用RAII,就可以非常好地工作。但是,我並沒有成功地使用boost :: threads,因爲它不會將掛起的線程置於可警告的等待狀態,所以QueueUserAPC無法喚醒它們。

0

如果您不希望線程執行的函數的「程序員」處理「停止」事件,請讓線程執行處理「停止」事件的「您」的函數,以及何時那個事件沒有被髮信號執行「程序員」功能...

換句話說,「while(!event)」將在一個調用「job」函數的函數中。

代碼示例。

typedef void (*JobFunction)(LPVOID params); // The prototype of the function to execute inside the thread 

struct structFunctionParams 
{ 
    int iCounter; 
    structFunctionParams() 
    { 
     iCounter = 0; 
    } 
}; 

struct structJobParams 
{ 
    bool bStop; 
    JobFunction pFunction; 
    LPVOID pFunctionParams; 
    structJobParams() 
    { 
     bStop = false; 
     pFunction = NULL; 
     pFunctionParams = NULL; 
    } 
}; 

DWORD WINAPI ThreadProcessJob(IN LPVOID pParams) 
{ 
    structJobParams* pJobParams = (structJobParams*)pParams; 
    while(!pJobParams->bStop) 
    { 
     // Execute the "programmer" function 
     pJobParams->pFunction(pJobParams->pFunctionParams); 
    } 

    return 0; 
} 


void ThreadFunction(LPVOID pParams) 
{ 
    // Do Something.... 
    ((structFunctionParams*)pParams)->iCounter ++; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    structFunctionParams stFunctionParams; 

    structJobParams stJobParams; 
    stJobParams.pFunction = &ThreadFunction; 
    stJobParams.pFunctionParams = &stFunctionParams; 




    DWORD dwIdThread = 0; 
    HANDLE hThread = CreateThread( 
     NULL, 
     0, 
     ThreadProcessJob, 
     (LPVOID) &stJobParams, 0, &dwIdThread); 
    if(hThread) 
    { 
      // Give it 5 seconds to work 
     Sleep(5000); 
     stJobParams.bStop = true; // Signal to Stop 
     WaitForSingleObject(hThread, INFINITE); // Wait to finish 
     CloseHandle(hThread); 
    } 
} 
+0

現在您正在進入整個工作/作業池系統。另外,這並不能解決繁忙循環中取消作業的問題。 – 2012-06-14 11:00:20

+0

如果我使用while(!event),用戶函數(job)將會運行並且永遠不會退出(注意thread_function中的while(1)循環)=>包裝函數是無用的 –

+0

@infact - 取消不是問題:) –