Почему Thread не умирает?
От: Abuserrr  
Дата: 26.07.06 17:40
Оценка:
Есть клиент-серверное приложение. Клиент время от времени посылает сообщения на сервер (сервер их обрабатывает и сохраняет в БД). Для этого был создан класс скажем Server:MarshalByRefObject
в котором собственно идет отсылка сообщения Server.SendToServer().
Далее на клиенте время от времени отсылаються сообщения на сервер:

private static Thread m_SendToServerThread;
private static int m_WaitDelay=1000*60*12; 
private static System.Threading.Timer m_WaitForSend;
public Send(Queue m_Queue)
{
bool isNotSent=true;
while (m_Queue.Count>0)
{

SendArgs argsToSend=m_Queue.Dequeue() as SendArgs;

while (isNotSent)
{
    try
    {                    
        SendToServerClass sts=new SendToServerClass(argsToSend);
        m_SendToServerThread=new Thread(new ThreadStart(sts.SendToServerMethod));
        m_SendToServerThread.Start();
        m_WaitForSend.Change(m_WaitDelay, Timeout.Infinite);
        m_SendToServerThread.Join();
        m_WaitForSend.Change(Timeout.Infinite, Timeout.Infinite);
        m_SendToServerThread=null;
        if (sts.isError && sts.Exception!=null)
        {
            throw sts.Exception;
        }
        if (sts.IsSent)
        {
           isNotSent=false;                        
        } 
    }
    catch (Exception ex)
    {
        Thread.Sleep(12000);//Send failed. Try again in 12 seconds
    }
}

}

}

private static void onWaitTimer(object p_state)
{
    if (m_SendToServerThread!=null && m_SendToServerThread.IsAlive)
    {
            m_SendToServerThread.Abort(); 
        }
}


public class SendToServerClass
{
    private MessageEventArgs m_argsToSend;
    private bool m_isSent;
    private bool m_WasError;
    private Exception m_Exception;
    public bool IsSent
    {
    get { return m_isSent; }
    }

    public bool isError
    {
        get { return m_WasError; }
    }

    public Exception Exception
    {
        get { return m_Exception; }
    }

    public SendToServerClass(MessageEventArgs p_argsToSend)
    {
        m_isSent=false;
        m_WasError=false;
        m_Exception=null;
           m_argsToSend=p_argsToSend;
    }
    public void SendToServerMethod()
    {
        try
        {
            Server.Instance.SendToServer(m_argsToSend);
            m_isSent=true;
        }
        catch (Exception ex)
        {
            m_Exception=ex;
            m_WasError=true;
            m_isSent=false;
        }
    }
}


В большинстве случаев все работает нормально, но где-то раз в три дня интенсивного исспользования m_SendToServerThread подвисает и соответственно остальные сообщения не отсылаються, так как мы ждем отсылки сообщения m_SendToServerThread.Join(); (ждать надо обезатьельно, так как порядок важен). Для решения этой проблемы ввел System.Threading.Timer, но m_SendToServerThread.Abort(); не всегда убивает поток. В тех случаях когда не убивает, поток просто переходит в состояние ThreadState.AbortRequested и никогда из него не выходит Научился воспроизводить это зависание (если клиент и БД находяться на одном компе, а сервер на втором, и в момент отсылки сообщения выключить компьютер с клиентом, то это зависание и происходит, даже если потом востановить соединение), так что тестировать возможно. Сервер не умирает, и до него возможно достучаться с клиента. Вопрос в том, как убить этот поток, чтоб не происходило этого зависания.

з.ы. Извиняюсь за такой обьемный вопрос, просто никак не могу решить эту проблему
Re: Почему Thread не умирает?
От: tyger Россия  
Дата: 27.07.06 04:52
Оценка:
Здравствуйте, Abuserrr, Вы писали:

<skipped>

A>В большинстве случаев все работает нормально, но где-то раз в три дня интенсивного исспользования m_SendToServerThread подвисает и соответственно остальные сообщения не отсылаються, так как мы ждем отсылки сообщения m_SendToServerThread.Join(); (ждать надо обезатьельно, так как порядок важен). Для решения этой проблемы ввел System.Threading.Timer, но m_SendToServerThread.Abort(); не всегда убивает поток. В тех случаях когда не убивает, поток просто переходит в состояние ThreadState.AbortRequested и никогда из него не выходит Научился воспроизводить это зависание (если клиент и БД находяться на одном компе, а сервер на втором, и в момент отсылки сообщения выключить компьютер с клиентом, то это зависание и происходит, даже если потом востановить соединение), так что тестировать возможно. Сервер не умирает, и до него возможно достучаться с клиента. Вопрос в том, как убить этот поток, чтоб не происходило этого зависания.


A>з.ы. Извиняюсь за такой обьемный вопрос, просто никак не могу решить эту проблему


Хм...
Если это настолько критично, может попробывать "бросить" этот повисшый поток и создать другой заново (предварительно конечно сделав все возможное для удаления повисшего)...
Возможно, итоге (по какому-то внутреннему таймауту) повысший поток и отвалится...
Но так можно поступить только если уже ничего больше не помогает... и последить первое время за расходом памяти и ресурсов....
Re: Почему Thread не умирает?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 27.07.06 06:13
Оценка:
Здравствуйте, Abuserrr.

Посмотрите здесь
Автор: TK
Дата: 17.07.06
, возможно найдете полезную информацию.
Re[2]: Почему Thread не умирает?
От: Abuserrr  
Дата: 27.07.06 10:08
Оценка:
Здравствуйте, tyger, Вы писали:

T>Хм...

T>Если это настолько критично, может попробывать "бросить" этот повисшый поток и создать другой заново (предварительно конечно сделав все возможное для удаления повисшего)...
T>Возможно, итоге (по какому-то внутреннему таймауту) повысший поток и отвалится...
T>Но так можно поступить только если уже ничего больше не помогает... и последить первое время за расходом памяти и ресурсов....

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

public class SendToServerClass
{
    private MessageEventArgs m_argsToSend;
    private bool m_isSent;
    private bool m_WasError;
    private Exception m_Exception;
    private Thread m_SendInClass;

    public bool IsSent
    {
    get { return m_isSent; }
    }

    public bool isError
    {
        get { return m_WasError; }
    }

    public Exception Exception
    {
        get { return m_Exception; }
    }

    public SendToServerClass(MessageEventArgs p_argsToSend)
    {
        m_isSent=false;
        m_WasError=false;
        m_Exception=null;
           m_argsToSend=p_argsToSend;
    }
    public void SendToServerMethod()
    {
        try
        {
            m_SendInClass=new Thread(new ThreadStart(Send));
        m_SendInClass.Start();
        m_SendInClass.Join();
            m_isSent=true;
        }
        catch (Exception ex)
        {
            if (m_SendInClass!=null && m_SendInClass.IsAlive)
        {
        m_SendInClass.Abort();
        }
            m_Exception=ex;
            m_WasError=true;
            m_isSent=false;
        }
    }

    private void Send()
    {
    try
    {
        Server.Instance.SendToServer.SendMessageToServerSync(m_argsToSend);
    }
    catch (Exception ex)
    {
        m_Exception=ex;
        m_WasError=true;
        m_isSent=false;
    }
    }
}


Недостаток такой, что поток, который делает Server.Instance.SendToServer так и продолжает жить (хоть и в редких случаях, но все же). И в таком случае при закрытии приложения, оно продолжает висеть в процессах

И еще вопрос, когда я делаю m_SendInClass.Abort(); в SendToServerMethod что первое должно выполниться, кетч в методе Send или продолжиться выполнение кетча в SendToServerMethod? Или все это будет происходить паралельно и приведет к неоднозначности?
Re[3]: Почему Thread не умирает?
От: romangr Россия  
Дата: 28.07.06 05:40
Оценка:
Здравствуйте, Abuserrr, Вы писали:

A>Недостаток такой, что поток, который делает Server.Instance.SendToServer так и продолжает жить (хоть и в редких случаях, но все же). И в таком случае при закрытии приложения, оно продолжает висеть в процессах


Попробуйте у потока выставить IsBackground = true;
... << RSDN@Home 1.2.0 alpha rev. 0>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.