web-dev-qa-db-ja.com

一時停止および再開が可能なタスクハンドラーの設計

タイトルは状況を正確に説明しているとは思いません。説明がおかしいことをお詫びします。

私はC++でソフトウェアシステムを作成しようとしていますが、それは重い仕事(特定のファイルまたは感染がないかファイルシステムをスキャンするか、ファイルをある場所から別の場所にコピー/移動する)になります。このシステムには、ユーザーが操作を一時停止して再開する機会を提供するインタラクティブコンポーネントがあります。ユーザーインターフェースがあるので、問題を分離するために、別の実行スレッド(同じプロセス内)または別のプロセス(インターフェースと操作をプロセスごとに分離する必要がある場合)でジョブを実行することを計画しています境界)。 UI要求処理ロジックがジョブハンドラーに忍び込みたくありません。では、システムをどのように設計すればよいですか?ここではどの(同期)プリミティブを使用する必要がありますか?

非同期プログラミングは初めてです。維持するデータ構造(進行状況、現在進行中の項目、再開中の整合性のチェック、まだ完了しているジョブの一部)は、アプリケーションに完全に依存することを理解しています。しかし、この問題に取り組む一般的な方法はありますか?プラットフォームに依存しないアプローチを探しています。

これは議論の余地があり、正解は1つではないかもしれませんが、提案があれば役立つと思います。

2
rranjik

独自のスレッドで実行されるジョブ処理クラスでこれが行われるのを見てきました。それはこのようなものでした:

_class JobQueue {
public:
    JobQueue();
    ~JobQueue();

    void EnqueueJob(Job newJob);
    void ResumeProcessing();
    void PauseProcessing();
    bool IsProcessing();

private:
    std::queue<Job> jobs;
    bool processing {false}; // May need more states, but keeping it simple here
    mutex jobQueueMutex;

    void ProcessLoop();
};
_

mutexは、ニーズにとってより便利で効率的であれば、別のタイプのプリミティブにすることができます。しかし、一般的な実装は次のようになります。

_void JobQueue::EnqueueJob(Job newJob)
{
    std::lock_guard<std::mutex> lk(jobQueueMutex);

    jobs.Push_back(newJob);
}

void JobQueue::ResumeProcessing()
{
    std::lock_guard<std::mutex> lk(jobQueueMutex);

    processing = true;
}

void JobQueue::PauseProcessing()
{
    std::lock_guard<std::mutex> lk(jobQueueMutex);

    processing = false;
}

bool IsProcessing()
{
    std::lock_guard<std::mutex> lk(jobQueueMutex);

    return isProcessing;
}

void JobQueue::ProcessLoop()
{
    while (1)
    {
        std::unique_lock<std::mutex> lk(jobQueueMutex);
        Job* nextJob = nullptr;
        if (jobs.size() > 0)
        {
            nextJob = jobs.pop_front();
        }
        lk.unlock();

        if (nextJob != nullptr)
        {
            nextJob->Process();
        }

        while (!isProcessing) {} // Probably don't want to busy wait, just an example. Could use semaphore or other mechanism
    }
}
_

ここでの考え方は、UIスレッドまたはその他のスレッドでEnqueueJob()を呼び出すことです。一時停止、再開、または処理が任意のスレッドで発生しているかどうかを確認することもできます。 ProcessLoop()関数は、処理スレッドで実行されます。

2
user1118321