Progettazione di un gestore di attività in pausa e riprende

2

Non penso che il titolo descriva esattamente la situazione. Mi scuso per la cattiva descrizione.

Sto provando a scrivere un sistema software, in C ++, che avrà un lavoro pesante (scansione del file system per un particolare file o per infezioni, o semplicemente copia / spostamento di un file da un posto a un altro). Questo sistema ha un componente interattivo che offre all'utente la possibilità di sospendere e riprendere l'operazione. Dato che abbiamo un'interfaccia utente, per ottenere una separazione delle preoccupazioni, sto pianificando di eseguire il lavoro su un thread di esecuzione separato (all'interno dello stesso processo) o un processo diverso (se l'interfaccia e l'operazione devono essere separate dal processo confini). Non voglio che la logica di gestione delle richieste dell'interfaccia utente si insinui nel gestore del lavoro. Ora, come dovrei progettare il sistema? Quali primitive (sincronizzazione) dovrei usare qui?

Sono nuovo alla programmazione asincrona. Capisco che, le strutture dati da mantenere (avanzamento, elemento corrente in corso, verifica dell'integrità durante la ripresa, parte del lavoro che è stato completato ancora) dipenderanno esclusivamente dall'applicazione. Tuttavia, esiste un modo generale per affrontare questo problema? Sto cercando un approccio indipendente dalla piattaforma.

Presumo che questo sia discutibile e potrebbe non esserci una risposta corretta, ma qualsiasi suggerimento sarebbe d'aiuto.

    
posta rranjik 03.07.2018 - 13:12
fonte

1 risposta

2

Ho visto questo fatto con una classe di elaborazione del lavoro che viene eseguita sul proprio thread. Sembrava qualcosa del genere:

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();
};

Il mutex può essere un altro tipo di primitivo se è più conveniente / efficiente per le tue esigenze. Ma un'implementazione tipica sarebbe una cosa del genere:

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
    }
}

L'idea è che chiameresti EnqueueJob() sul thread dell'interfaccia utente o su qualsiasi altro thread. È possibile mettere in pausa, riprendere o controllare se l'elaborazione si sta verificando su qualsiasi thread. La funzione ProcessLoop() verrebbe eseguita sul thread di elaborazione.

    
risposta data 03.07.2018 - 17:19
fonte