Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > System.Timer и Pause


Автор: DragonFire 1.1.2010, 19:45
Задача такая - есть N объектов, у каждого из них есть встроенный таймер. Таймер может сработать в произвольное (заранее не известное) время. 
При срабатывании таймера у какого-либо объекта необходимо выполнить длинный ресурсоемкий код. Но если все делать в лоб, пока код выполняется, срабатывают (или могут сработать) другие таймеры и логика программы будет нарушена.
Мне необходимо "ставить на паузу" все остальные таймеры, при срабатывании одного, а после выполнения кода обработчика, возобновлять работу.
Как такое реализовать?

Автор: Экскалупатор 1.1.2010, 20:37
Создай класс, который в отдельном потоке будет управлять всеми остальными потоками.

Автор: Heinzz 1.1.2010, 21:32
я бы сделал иначе. Создайте очередь в которую будут попадать ваши объекты при срабатывании таймера. Обрабатывайте ее последовательно. Что-то останавливать/запускать - лишние затраты ресурсов если много объектов.

Автор: Экскалупатор 1.1.2010, 22:11
Цитата(Heinzz @  1.1.2010,  20:32 Найти цитируемый пост)
я бы сделал иначе.

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

Автор: DragonFire 2.1.2010, 15:13
Очередь не подойдет, так как моделируется псевдореальное время. 

Задача такая: есть СМО (система массового обслуживания). В случайные моменты времени в систему приходят клиенты (поток поступления клиентов, со непредсказуемым временем срабатывания), которые обрабатываются мастерами (еще N потоков, у каждого свое непредсказуемое время срабатывания).

Проблема в том, что при срабатывании какого-либо события выполняется код, которые отнимает некое время. Из-за этого клиент, который должен был придти через 4 еденицы времени, приходит через 5 едениц (т.к. когда он пришел, выполнялся некий посторонний код).

Из-за таких накладок получается мешанина событий несвязанный нормально. Нуобходимо перед выполнением любого сложного кода блокировать все остальные таймеры, чтобы не смешивать "время из предметной области, за которое отвечают таймеры" и "симтемное время, которое тратится на выполнение кода".

Автор: Экскалупатор 2.1.2010, 15:29
как я уже говорил: 
Цитата(Экскалупатор @  1.1.2010,  19:37 Найти цитируемый пост)
Создай класс, который в отдельном потоке будет управлять всеми остальными потоками. 

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

Автор: DragonFire 2.1.2010, 16:37
В том то и дело, что поток прихода клиента должен быть просто заморожен на время выполнения кода smile Чтобы не возникало таких ситуаций... 

Автор: kobra 2.1.2010, 17:46
мне кажется что постановка задачи не коректна, или задача невыполнима.
если кажды клиент может воити в систему когда угодно (чтобы была емуляция реального времени), значит нелзя блокировать его.
но если не блокировать, то произаидет мешанина событий.
взаимо исклучающие условия

Автор: Экскалупатор 2.1.2010, 17:54
DragonFire, ну тогда делай через класс, который будет управлять всем остальным. но как уже сказали, весьма странное условие. лучше все таки очередь(ИМХО).

Автор: DragonFire 3.1.2010, 02:27
Все оказалось просто:
Код

//Клиент
    public class Client
    {
        //Время прихода
        public Double ComingTime;
        //Текущее время
        public Double NowTime;
        //Таймер
        private Timer Timer;
        private Stopwatch Stopwatch;

        public event EventHandler Coming;

        public Client()
        {            
            Timer = new Timer();            
            Timer.AutoReset = false;            
            Timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed);
            Stopwatch = new Stopwatch();            
        }

        public void NewClient(Double NowTime, Double ComingTime)
        {
            this.NowTime = NowTime;
            this.ComingTime = ComingTime;
            Timer.Interval = ComingTime * Setup.M;
            Stopwatch.Reset();
            Timer.Start();
            Stopwatch.Start();
        }

        public void Pause()
        {
            Stopwatch.Stop();
            Timer.Stop();
        }

        public void Resume()
        {
            Timer.Interval = ComingTime * Setup.M - Stopwatch.ElapsedMilliseconds / Setup.M;
            Timer.Start();
            Stopwatch.Start();
        }

        public void Stop()
        {
            Timer.Stop();
            Stopwatch.Stop();
        }

        
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            NowTime += ComingTime;
            if (Coming != null)
                Coming(this, EventArgs.Empty);
        }
    }

...

void Client_Coming(object sender, EventArgs e)
        {
            Client.Pause();
            
             РЕСУРСОЕМКИЙ КОД              

            Client.Resume();
        }

Смысл в добавление Stopwatсh чтобы отследить время работы таймера....

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)