Прерывание потока в ASP.NET

protected System.Threading.Thread m_searchthread = null;

Вопрос: Я реализовал алгоритм поиска, который пользователь может запустить с веб-сайта ASP.NET.

Когда пользователь нажимает кнопку «Пуск», выполняется этот код:

m_searchthread = new System.Threading.Thread(new System.Threading.ThreadStart(Search));
m_searchthread.IsBackground = true;
m_searchthread.Start();

Теперь я хочу сделать возможным прерывание потока поиска. Итак, пользователь нажимает кнопку «Прервать», и этот код выполняется:

m_searchthread.Abort();

Теперь моя проблема: обратная передача кнопки прерывания сбрасывает m_searchthread в NULL...

Мне известно, что поток должен быть прерван с помощью флага. Основная проблема заключается в следующем: как остановить поток, если вы потеряли все переменные?


person Stefan Steiger    schedule 27.07.2010    source источник
comment
Вместо того, чтобы выделять жирным шрифтом то, о чем вы знаете, не могли бы вы опубликовать код своего алгоритма, чтобы его можно было улучшить, чтобы использовать флаг? Суть проблемы в вашем алгоритме, а не в том, что вы теряете переменные при постбэке (это нормальное поведение страницы ASP.NET)   -  person Darin Dimitrov    schedule 27.07.2010
comment
Пожалуйста, не используйте ‹h1› таким образом, я удалил его. Вместо этого используйте * для выделения.   -  person Abel    schedule 27.07.2010
comment
Использование флага довольно просто, это цикл while... Проблема только в том, что флаг для потока ошибочно остановит поток при обратной передаче.   -  person Stefan Steiger    schedule 27.07.2010
comment
Вы можете знать, что вам не следует использовать Thread.Abort, но не все в мире. Указание на то, что это не является хорошей практикой, по-прежнему полезно и актуально для этой темы.   -  person Phil Gan    schedule 27.07.2010


Ответы (5)


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

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

Я не пытаюсь комментировать, как вы выполняете свою асинхронную задачу.

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

Вы столкнетесь с этой проблемой всякий раз, когда у вас есть какое-то состояние на сервере, которое вам нужно запомнить между обратными передачами. ViewState — это то, как элементы управления ASP.NET запоминают свое содержимое между обратными передачами без необходимости их повторного заполнения каждый раз.

person Adam Houldsworth    schedule 27.07.2010
comment
Да, вы говорите это: это невозможно без статических переменных. Что на самом деле очень и очень плохая идея. - person Stefan Steiger; 27.07.2010
comment
@Quandary Я стараюсь не высказывать никаких мнений об использовании какого-либо состояния сервера - я недостаточно делаю ASP.NET, чтобы иметь ценный вклад :), поэтому я поверю вам на слово. - person Adam Houldsworth; 27.07.2010

Прямая проблема здесь заключается в том, что вы пытаетесь использовать переменную-член (поле) для хранения потока.

Если вы сохраните его как Session["MyThreadKey"] = myThread;, вы, по крайней мере, сможете вернуть свой поток в следующем постбэке. Как 2_

И тогда вы можете начать думать о том, как избежать Thread.Abort.

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


Как уже отмечалось, это будет работать только для решения с одним сервером. Лучшим подходом во всем было бы определение службы (WCF) для выполнения поиска.

person Henk Holterman    schedule 27.07.2010
comment
Thread не [Serializable], поэтому я бы не рекомендовал этот подход. В тот день, когда вы решите использовать ферму серверов и внепроцессное хранилище сеансов, этот код не будет работать. - person Darin Dimitrov; 27.07.2010
comment
@Darin: правильно, но многопоточный поиск вообще не будет работать на ферме серверов. - person Henk Holterman; 27.07.2010
comment
Я согласен. Мне нужно сделать это как внешнюю службу и сохранить UID в переменной сеанса, с помощью которой я могу вызвать внешнюю службу, чтобы остановить поток с этим UID. - person Stefan Steiger; 28.07.2010

Почему бы не сохранить флаг в Session или ViewState и не выполнить проверку в событии загрузки страницы.

person James    schedule 27.07.2010
comment
Thread не [Serializable], поэтому я бы не рекомендовал этот подход. В тот день, когда вы решите использовать ферму серверов и внепроцессное хранилище сеансов, этот код не будет работать. - person Darin Dimitrov; 27.07.2010
comment
@Darin: Да, видел ваш комментарий, я изменил свой ответ, чтобы игнорировать сохранение потока в сеансе. - person James; 27.07.2010

Не запускайте/останавливайте задания со страницы, потому что это опасно, и вы не можете контролировать выполнение и запуск задач.

Я предлагаю вам использовать Quartz.NET. Есть полезный ответ об использовании его в Asp.NET: Как использовать Quartz.net с ASP. НЕТТО

person onof    schedule 27.07.2010

Чтобы остановить поток на основе флага, вы должны реализовать его следующим образом:

  1. Определите сам флаг в статическом классе или модуле, где он доступен для потока:

    bool StopTheThread = false;
    
  2. Внутри вашего потока проверьте наличие этого флага где-то внутри вашего цикла, чтобы изящно выйти из потока!

    void SearchProc()
    {
        bool exitCond = False;
        while (!exitCond)
        {
            //some execution
            //some execution
            //some execution
            //check for the thread-abort flag:
            if (StopTheThread)
            {
                System.Threading.Thread.Suspend(); //this will suspend the current thread
            }
        }
    }
    
person Prahlad Yeri    schedule 12.03.2011