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


Автор: Zhenyok 18.12.2007, 08:51
Доброго времени суток. Пишу сервер на c#(многопоточный, общается через TCP с драйверами), столкнулся с такой проблемой: остановливаются таймеры(System.Timers), то один ,то другой, то через пару часов, то через месяц.   smile. Думал что проблемы в исчерпании пула системных потоков-нет, все нормально, потоков хватает, а таймер останавливается
Вот код таймеров посылки тестовых команд драйверам(у них AutoReset = true)
Код

private void TestCommandTimerCallback(object source, ElapsedEventArgs e)
{
SendTestCommand();
}

в SendTestCommand() выполняется socket.BeginSend

код таймера для работы с ключем AutoReset = false
Код

private void haspTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    haspTimer.Stop();
    CheckHaspStatus();
    haspTimer.Start();
}

где CheckHaspStatus() проверяет состояние ключа. 
Все вроде безобидно, но в чем дело - никак не пойму smile 

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

Еще подозрения падали на загруженность процессора - тоже не то(делал тесты)
Общих ресурсов нет, deadlock-а тоже.

Главное не на всех машинах падает, а только на сервере фирмы smile !!!!
Может из-за конфигурации системы, или hyper threading-а
Приложение компилировалось на MSVS2003, на сервере стоит framework 1
Может кто знает в чем причина подскажите хоть в какую сторону рыть, а то уже голова скоро лопнет smile 

Автор: tol05 18.12.2007, 12:05
Socket.EndSend() когда вызывается?

И код давай сюда. Иначе никто не ответит.

Автор: Zhenyok 18.12.2007, 14:07
вот метод
Код

private void SendTestCommand()
        {
            if(!isSocketClosed)
            {
            
                byte[]        command     = new byte[6];
                DateTime    time     = DateTime.Now;
                command[0] = (byte)time.Minute;
                command[1] = (byte)time.Second;
                command[2] = BitConverter.GetBytes(528)[0];
                command[3] = BitConverter.GetBytes(528)[1];
                try
                {
                    socket.BeginSend(command,0,command.Length,SocketFlags.None,new AsyncCallback(SendCallBack),socket);            Log.AddInfo(this.ToString()+": Begin send test command");
                
                }
                catch(Exception ex)
                {
                    Log.Add(this.ToString()+ex.ToString());
                    CloseSocket();
                }
            }
        }

а вот метод SendCallBack
Код



private void SendCallBack(IAsyncResult ar)
        {
            try
            {
                Socket soc = (Socket)ar.AsyncState;
                if (soc.Connected)
                {
                    int byteSend = soc.EndSend(ar);
                    Log.AddInfo(this.ToString() + ": End send test command");
                }
                else
                {

                    Log.Add("SendCallback SOCKET " + this.ToString() + " not connected");
                    CloseSocket();
                }

            }
            catch (SocketException ex)
            {
                Log.Add("SendCallback " +this.ToString()+ ex.ToString());
                CloseSocket();
            }
            catch (System.Exception ex)
            {
                Log.Add(ex.StackTrace);
                Log.Add("SendCallback " +this.ToString()+ ex.ToString());

            }

        }


Вот функции приема данных
Код

    private void BeginRecieve() 
        {
            try 
            {
                StateObject state = new StateObject();
                socket.BeginReceive(state.buffer,0,StateObject.BUFFER_SIZE,SocketFlags.None,new AsyncCallback(ReceiveCallback),state);
            
            }
            catch(Exception ex) 
            {
                Log.Add(this.ToString()+ex.ToString());
                CloseSocket();
            }
            
        }
        

        private void ReceiveCallback(IAsyncResult ar) 
        {
            if( isDisposed || isSocketClosed || !socket.Connected )
            {
                return; 
            }
            
            try 
            {
                controlTimer.Stop();
                StateObject state = (StateObject)ar.AsyncState;
                int byteRead = socket.EndReceive(ar);
                if(byteRead > 0) 
                {
                    byte[] response = new byte[byteRead];
                    Array.Copy(state.buffer, response, byteRead);
                    RaiseMessageEvent(response);                
                }
                else
                {
                    SendTestCommand();
                } 
                if(!isSocketClosed)
                {
                        socket.BeginReceive(state.buffer,0,StateObject.BUFFER_SIZE,SocketFlags.None,new AsyncCallback(ReceiveCallback),state);
                       
                }
                
            } 
            catch(Exception ex)
            {
                Log.Add(this.ToString()+ex.ToString());
                CloseSocket();
            }
        }


вот методы чтения и записи в сокет

Добавлено через 35 секунд
все что есть

Автор: ivashkanet 18.12.2007, 14:11
Цитата(Zhenyok @  18.12.2007,  08:51 Найти цитируемый пост)
    haspTimer.Stop();
   CheckHaspStatus();
    haspTimer.Start();

А эксепшин не может здесь выскочить?

Автор: Zhenyok 18.12.2007, 14:58
была такая теория, тестировал порождением нового exception, бесполезно, проглатывает его, т.к. метод выполняется в системном потоке.
Но теория не подтвердилась

Автор: tol05 18.12.2007, 15:44
ИМХО если просто останавливаются таймеры, то это значит, что их в очередной раз просто не запустили. Поэтому я согласен с ivashkanet
 (ivashkanet, блин, твой новый аватар просто крышу рвет)

smile 

Нужно искать в CheckHaspStatus()

Значит все-таки в ней валится...

Цитата(Zhenyok @  18.12.2007,  07:51 Найти цитируемый пост)
то через пару часов, то через месяц


Автор: Zhenyok 18.12.2007, 16:32
вот лог, где ясно видно, что haspTimer был взведен, но не выполнтлся, а функция отработала корректно
8:17:21.62 TestCommandTimerCallback work 24 all 1000
8:17:21.62 SOCKET 0: TestCommand timer elapsed
8:17:21.62 SOCKET 0: Begin send test command
8:17:21.62 SOCKET 0: SendTestCommand called
8:17:21.62 SOCKET 0: End send test command
8:17:21.62 TestCommandTimerCallback work 24 all 1000
8:17:21.62 SOCKET 1: TestCommand timer elapsed
8:17:21.62 SOCKET 1: Begin send test command
8:17:21.62 SOCKET 1: SendTestCommand called
8:17:21.62 SOCKET 1: End send test command
8:17:21.62 TestCommandTimerCallback work 24 all 1000
8:17:21.62 SOCKET 2: TestCommand timer elapsed
8:17:21.62 SOCKET 2: Begin send test command
8:17:21.62 SOCKET 2: SendTestCommand called
8:17:21.62 SOCKET 2: End send test command
8:17:21.62 ReceiveCallback work 25 all 999
8:17:21.62 ReceiveCallback work 25 all 999
8:17:21.78 haspTimer_Elapsed start    haspTimerStoped = False
8:17:21.78 HaspTimer.Stop()  haspTimerStoped = False
8:17:21.78 work 24 all 1000
8:17:21.78 Hasp status: 1 StatusOk
8:17:21.109 ReceiveCallback work 24 all 999
8:17:21.125 Hasp status: 2 StatusOk
8:17:21.125 Hasp status: 3 StatusOk
8:17:21.140 Hasp status: 4 StatusOk
8:17:21.140 Hasp status 5 : StatusOk
8:17:21.140 Hasp status: 6 StatusOk
8:17:21.140 Hasp status: 7 StatusOk
8:17:21.140  hasp return True
8:17:21.140 CheckHaspStatus()1 = true  buffermanStopedByHasp =  False
8:17:21.140 End HaspTimer_Elapsed    haspTimer.Enabled = True

14.12.2007 
8:17:22.125 ReceiveCallback work 25 all 999
8:17:22.125 ReceiveCallback work 25 all 999
8:17:22.125 TestCommandTimerCallback work 24 all 1000
8:17:22.125 SOCKET 0: TestCommand timer elapsed
8:17:22.125 SOCKET 0: Begin send test command
8:17:22.125 SOCKET 0: SendTestCommand called
8:17:22.125 SOCKET 0: End send test command
8:17:22.125 TestCommandTimerCallback work 24 all 1000
8:17:22.125 SOCKET 1: TestCommand timer elapsed
8:17:22.125 SOCKET 1: Begin send test command
8:17:22.125 SOCKET 1: SendTestCommand called
8:17:22.125 SOCKET 1: End send test command
8:17:22.125 TestCommandTimerCallback work 24 all 1000
8:17:22.125 SOCKET 2: TestCommand timer elapsed
8:17:22.140 SOCKET 2: Begin send test command
8:17:22.140 SOCKET 2: SendTestCommand called
8:17:22.140 SOCKET 2: End send test command
8:17:22.140 haspTimer_Elapsed start    haspTimerStoped = False
8:17:22.140 HaspTimer.Stop()  haspTimerStoped = False
8:17:22.140 work 24 all 1000
8:17:22.140 Hasp status: 1 StatusOk
8:17:22.140 ReceiveCallback work 24 all 999
8:17:22.187 Hasp status: 2 StatusOk
8:17:22.187 Hasp status: 3 StatusOk
8:17:22.203 Hasp status: 4 StatusOk
8:17:22.203 Hasp status 5 : StatusOk
8:17:22.203 Hasp status: 6 StatusOk
8:17:22.203 Hasp status: 7 StatusOk
8:17:22.203  hasp return True
8:17:22.203 CheckHaspStatus()1 = true  buffermanStopedByHasp =  False
8:17:22.203 End HaspTimer_Elapsed    haspTimer.Enabled = True

14.12.2007 
8:17:23.140 ReceiveCallback work 25 all 999
8:17:23.140 ReceiveCallback work 25 all 999
8:17:23.140 TestCommandTimerCallback work 24 all 1000
8:17:23.140 SOCKET 0: TestCommand timer elapsed
8:17:23.140 SOCKET 0: Begin send test command
8:17:23.140 SOCKET 0: SendTestCommand called
8:17:23.140 SOCKET 0: End send test command
8:17:23.140 TestCommandTimerCallback work 24 all 1000
8:17:23.140 SOCKET 1: TestCommand timer elapsed
8:17:23.140 SOCKET 1: Begin send test command
8:17:23.140 SOCKET 1: SendTestCommand called
8:17:23.140 SOCKET 1: End send test command
8:17:23.140 TestCommandTimerCallback work 24 all 1000
8:17:23.140 SOCKET 2: TestCommand timer elapsed
8:17:23.140 SOCKET 2: Begin send test command
8:17:23.140 SOCKET 2: SendTestCommand called
8:17:23.203 SOCKET 2: End send test command
8:17:23.218 ReceiveCallback work 25 all 999

14.12.2007 
8:17:24.156 TestCommandTimerCallback work 24 all 1000
8:17:24.156 SOCKET 0: TestCommand timer elapsed
8:17:24.156 SOCKET 0: Begin send test command
8:17:24.156 SOCKET 0: SendTestCommand called
8:17:24.156 SOCKET 0: End send test command
8:17:24.156 TestCommandTimerCallback work 24 all 1000
8:17:24.156 SOCKET 1: TestCommand timer elapsed
8:17:24.156 SOCKET 1: Begin send test command
8:17:24.156 SOCKET 1: SendTestCommand called
8:17:24.156 SOCKET 1: End send test command
8:17:24.156 TestCommandTimerCallback work 24 all 1000
8:17:24.156 SOCKET 2: TestCommand timer elapsed
8:17:24.156 SOCKET 2: Begin send test command
8:17:24.156 SOCKET 2: SendTestCommand called
8:17:24.156 SOCKET 2: End send test command
8:17:24.156 ReceiveCallback work 25 all 999
8:17:24.156 ReceiveCallback work 25 all 999
8:17:24.281 ReceiveCallback work 25 all 999 



я бы понял если там исключение, так нет же, не вылетает !!!

Автор: mr.DUDA 19.12.2007, 15:45
В крайнем случае можно вместо Start/Stop попробовать юзать булевский флаг:
Код
bool _ignoreTimerElapsed = false;

private void haspTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    if(_ignoreTimerElapsed) return;

    _ignoreTimerElapsed = true;
    try
    {
        CheckHaspStatus();
    }
    finally { _ignoreTimerElapsed = false; }
}


Вообще не очень понятно, почему используется Start/Stop и почему AutoReset=true...

Автор: Zhenyok 20.12.2007, 08:42
флаг можно использовать-не вопрос, я пытаюсь понять почему таймер в следующую секунду не запустился, хотя при выходе из haspTimer_Elapsed hasrTimer.Enabled = true, т.е. оп определению он должен сработать!!! А он не сработал. Есть ли какие-нить предпосылки для этого? Дело в системе или коде? Почему тогда на некоторых компах работает всегда, а на некоторых падает

Автор: mr.DUDA 20.12.2007, 10:29
Код странный. Во-первых, несколько обработчиков Elapsed могут выполниться одновременно т.к. таймер использует пул потоков для генерации события Elapsed. Во-вторых, AutoReset говорит о том что Elapsed будет выкинут 1 раз после Start. В-третьих, Start/Stop в каждом обработчике Elapsed... Наконец, не мешало бы поставить try..catch на метод CheckHaspStatus.

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