Почему вытесняется поток?
От: Shadedsun  
Дата: 10.09.08 15:44
Оценка:
Есть форма с двумя кнопками, одна кнопка — запустить поток с ресурсоёмкой задачей, другая — остановить его. Поток для задачи берется из ThreadPool. В качестве имитации задачи используется Thread.SpinWait или просто цикл:

void WorkItem(object state)
{    

    int iterations = 1000000000;
    
    while (!bStopWorkItem)
    {
        Thread.SpinWait(iterations);
        //MySpinWait(iterations);
    }        

    this.Invoke((Action)WorkItem_Stopped);
}

void MySpinWait(int iterations)
{
    for (; iterations > 0; iterations--) { }
}


Кнопка которая останавливает поток присваивает полю bStopWorkItem значение true, и задача просто покидает его.

Проблема в том, что если в качестве имитации задачи использовать Thread.SpinWait, то через некоторое время (3-15 сек) GUI перестаёт отвечать, в то время как при MySpinWait задачу можно снять в любое время. Собсно, вопрос в том и заключается: почему зависает GUI?
Подобное поведение характерно не только для Thread.SpinWait. У меня есть проект, где читается директория при помощи API-функций FindFirstFile, FindNextFile, и таже проблема актуальна. Причём, если чтение идет с сетевого диска или CD, то проблем нет (IMHO: в процессе чтения с медленного носителя используются задержки освобождающие кванты), но если читать с быстрого HDD, а тем более, если читать два раза подряд одну и туже директорию (при втором чтении будет использована инфа с кеша), то подвисание гарантированно.
Вот готовый проект, на примере которого видно всё, о чём я говорил:ThreadDemo01.zip

PS

Втророй пример, более навороченный, но делает приблизительно тоже: ThreadDemo02.zip

Из второго примера видно, что если при подвешенном GUI, задачу всё же удаётся остановить, то и GUI начинает функционировать, как ни в чём не бывало, нормально (за остановку по таймауту отвечает поле "Emergency counter", где одна единица соответствует примерно одной секунде).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.