1

最近は、Windows のスレッドについてもっと学ぼうとしています。私はこの実用的なアプリケーションを作ることを考えました:

「開始」ボタンが押されたときにいくつかのスレッドが開始されたとします。これらのスレッドが集中的であると仮定します (実行し続けているか、常に何らかの作業を行っています)。

このアプリには「停止」ボタンもあります。このボタンが押されると、すべてのスレッドが適切な方法で閉じられるはずです。つまり、リソースを解放し、作業を放棄して、[開始] ボタンが押される前の状態に戻ります。

アプリのもう 1 つの要求は、スレッドによって実行される関数に、「停止」ボタンが押されたかどうかを確認する命令を含めないようにすることです。スレッドで実行されている関数は、停止ボタンを気にする必要はありません。

言語: C++

OS: Windows

問題:

WrapperFunc(function, param)    
{
     // what to write here ?
     // if i write this:
     function(param);
     // i cannot stop the function from executing
}
  • スレッドを適切に停止できるようにするには、ラッパー関数をどのように作成すればよいですか? ( TerminateThread やその他の関数を使用せずに)

  • プログラマがメモリを動的に割り当てたらどうなるでしょうか? スレッドを閉じる前にそれを解放するにはどうすればよいですか?(「停止ボタン」を押してもスレッドはまだデータを処理していることに注意してください) new 演算子をオーバーロードするか、メモリを動的に割り当てるときに使用される事前定義された関数の使用を強制することについて考えました. ただし、これは、この 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,...);
4

3 に答える 3

0

スレッドが実行する関数の「プログラマー」に「停止」イベントを処理させたくない場合は、「停止」イベントを処理する「あなた」の関数をスレッドに実行させ、そのイベントがそうでない場合t signaled は「プログラマー」機能を実行します...

つまり、"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);
    }
}
于 2012-06-14T10:55:33.920 に答える
0

この同様の質問に対する私の回答を参照してください。

win32 アプリの高速シャットダウンを保証するにはどうすればよいですか?

基本的に、QueueUserAPC を使用して、例外をスローする proc をキューに入れることができます。例外は、スレッド プロシージャの「キャッチ」までバブルする必要があります。

使用しているライブラリが適度に例外を認識し、RAII を使用している限り、これは非常にうまく機能します。ただし、これをboost::threadsで正常に機能させることはできません。中断されたスレッドをアラート可能な待機状態にしないため、QueueUserAPCはそれらを起こすことができません。

于 2012-06-14T10:55:15.283 に答える
0

解決策の 1 つは、スレッドに動作を停止するように指示する何らかのシグナルを用意することです。多くの場合、これは通常はグローバルなブール変数ですfalseが、設定するtrueとスレッドに停止するように指示します。クリーンアップについては、スレッドから戻る前に、スレッドのメインループが完了したときに実行します。

つまり、次のようなものです。

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、実際の処理を行う -like 関数を呼び出します。ただし、時間がかかる可能性のある操作が含まれている場合は、最初の問題が再び発生します。

于 2012-06-14T10:24:34.133 に答える