Как сделать паузу во время выполнения, сохранить состояние и продолжить с того же момента позже? - PullRequest
10 голосов
/ 03 ноября 2011

У меня есть поток, который выполняет некоторую обработку.Я хотел бы иметь возможность остановить этот поток во время выполнения, каким-то образом сохранить его положение (и состояние объектов, над которыми он работает), а затем продолжить работу с этого места в более поздние сроки (то есть после перезагрузки компьютера).

В C # это невозможно, верно?А если нет, каков правильный дизайн для достижения этой функциональности?

Так что мое первоначальное желание состояло в том, чтобы иметь что-то вроде

class Foo : Task {   
    void override   Execute(){ 
        //example task
        while(someCondition){
        ...do stuff... 
        }
    }
}

и иметь возможность приостанавливать / сохранять в любой точке этогофункция.Когда функция заканчивается, все знают, что она завершена.В качестве альтернативы, возможно, это лучший способ сделать это

class Foo : Task {


    void override Execute(State previousState){
        //set someCondition, other stuff
        //IsPaused = false;
        previousState.setUpStuff();

        //example task
        while(someCondition){
            ...do stuff... 
            if(base.IsPauseRequested){
                 base.UpdateState(); //this would be a bit different but just to get the idea
                 base.IsPaused = true;
                 return;
            }
        }

        base.RaiseNotifyTaskComplete();
    }

}

Так что первый случай намного проще для других людей, которым нужно унаследовать мой базовый класс, поскольку им нужно только реализовать функцию Execute.Однако во втором случае они должны учитывать предыдущее состояние, а также управлять, где существуют хорошие точки паузы.Есть ли лучший способ сделать это?

Ответы [ 5 ]

5 голосов
/ 03 ноября 2011

То, что вы хотите, может быть выполнено с помощью сериализуемого конечного автоматаПо сути, вы изменяете свои локальные переменные на поля в классе и добавляете поле, которое сохраняет состояние - позицию в коде исходного метода.Этот класс будет [Serializable], и у него будет один метод, такой как MoveNext(), который выполняет часть работы и возвращает результат.При работе вы вызываете этот метод в цикле.Когда вы хотите остановиться, вы ждете, пока текущий вызов не завершится, выйдете из цикла и затем сериализуете конечный автомат на диск.

На основе сложности исходного метода и того, как часто вы хотите«Контрольная точка» (когда метод MoveNext() возвращается и вы можете продолжить или нет), конечный автомат может быть таким же простым, как наличие только одного состояния, или довольно сложным.

Компилятор C # делает очень похожепреобразование при компиляции блоков итераторов (и методов C # 5 async).Но он не предназначен для этой цели и не помечает сгенерированный класс [Serializable], поэтому я не думаю, что вы могли бы его использовать.Хотя чтение некоторых статей о том, как на самом деле осуществляется это преобразование, может помочь вам сделать то же самое самостоятельно.

1 голос
/ 03 ноября 2011

Это может быть легко достигнуто с помощью WF ... он имеет все необходимое для явной приостановки и возобновления задач (и он заботится о постоянстве для вас). Проверьте эту ссылку.

Возможно, не подходит для того, что вы хотите, но, возможно, стоит изучить.

0 голосов
/ 03 ноября 2011

Возможно, вы могли бы создать что-то подобное с деревом выражений или цепочкой методов. Настройте лямбды или маленькие методы для самых маленьких «атомарных» единиц работы, которые не могут быть прерваны. Затем объедините их в цепочку с «супервизором», который будет выполнять каждый из этих кусков по порядку, но ему будет приказано прекратить выполнение промежуточных инструкций, сохранить свою позицию вдоль цепочки, вернуться и дождаться возобновления. Если вам нужно имя шаблона, вы можете назвать его вариантом для посетителя.

0 голосов
/ 03 ноября 2011

Вы хотите сериализовать состояние вашего объекта, когда процесс приостановлен, а затем десериализовать его после перезапуска.

Очень наивной реализацией было бы создание двух статических методов в вашем классе задач Serialize / Deserialize, которые используют Linq для чтения / записи состояния вашего объекта в XML. Когда задача приостановлена, вызовите Serialize, который выдает объект как xml на диск, при перезапуске вызовите Deserialize, который читает xml. Существует также класс XmlSerializer , который может быть более надежным.

Несмотря на это, это сложная проблема с концептуально простым решением.

0 голосов
/ 03 ноября 2011

Я не могу ответить за C#, но в целом этот вопрос называется Постоянство , и не существует общего простого способа его решения (если только язык и система его не предоставляют).Вы не можете рассуждать в терминах одного потока, потому что рассматриваемый поток ссылается на некоторые другие (глобальные или кучные) данные.Этот вопрос также связан с сборкой мусора (поскольку как сборщики мусора, так и механизм постоянства имеют тенденцию сканировать всю живую кучу).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...