Почему вытесняется поток?
От: 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", где одна единица соответствует примерно одной секунде).
Re: $30 WMZ тому кто решит эту проблему
От: Shadedsun  
Дата: 16.09.08 14:33
Оценка:
S>После запуска с Thread.SpinWait, поводите мышью над кнопкой Stop, так GUI подвиснет быстрее.
S>Закоментируйте строчку с Thread.SpinWait(iterations) и разкоментируйте с MySpinWait(iterations), вы убедитесь, что при такой же загрузке проца GUI стабильно работоспособен.

Что бы легче было понять о чем идет речь, можете скачать видео с gmail.com (см. в черновиках)
логин: share.sasha
пароль: entershare

PS

Re[2]: $30 WMZ тому кто решит эту проблему
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 16.09.08 14:38
Оценка:
Здравствуйте, Shadedsun, Вы писали:

S>>После запуска с Thread.SpinWait, поводите мышью над кнопкой Stop, так GUI подвиснет быстрее.

S>>Закоментируйте строчку с Thread.SpinWait(iterations) и разкоментируйте с MySpinWait(iterations), вы убедитесь, что при такой же загрузке проца GUI стабильно работоспособен.

S>Что бы легче было понять о чем идет речь, можете скачать видео с gmail.com (см. в черновиках)

S>логин: share.sasha
S>пароль: entershare

S>PS


S>

А hyper threading есть?
Re: ICQ #367172706
От: Shadedsun  
Дата: 16.09.08 14:38
Оценка:
Re[3]: $30 WMZ тому кто решит эту проблему
От: Shadedsun  
Дата: 16.09.08 14:41
Оценка:
P>А hyper threading есть?
У Athlon64 X2 5000+ — скорее всего есть
У PentiumIII 1000 — скорее всего нету
Re: Почему вытесняется поток?
От: Experimenter Беларусь  
Дата: 16.09.08 17:16
Оценка:
Здравствуйте, Shadedsun, Вы писали:

S>Есть форма с двумя кнопками, одна кнопка — запустить поток с ресурсоёмкой задачей, другая — остановить его. Поток для задачи берется из ThreadPool. В качестве имитации задачи используется Thread.SpinWait или просто цикл:


S>
S>void WorkItem(object state)
S>{    

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

S>    this.Invoke((Action)WorkItem_Stopped);
S>}

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


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


S>Проблема в том, что если в качестве имитации задачи использовать Thread.SpinWait, то через некоторое время (3-15 сек) GUI перестаёт отвечать, в то время как при MySpinWait задачу можно снять в любое время. Собсно, вопрос в том и заключается: почему зависает GUI?

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


Не совсем уверен, что MySpinWait в Вашем примере выполняет какую-то работу. Об агрессивной оптимизации слышали? Я до недавнего времени тоже ничего не знал. Но взгляните сюда: http://forum.vingrad.ru/index.php?showtopic=180722&view=findpost&p=1310994. Поэтому и подвисаний нет. Я так думаю.
Re[2]: Почему вытесняется поток?
От: Shadedsun  
Дата: 18.09.08 14:50
Оценка:
Здравствуйте, Experimenter, Вы писали:

E>Не совсем уверен, что MySpinWait в Вашем примере выполняет какую-то работу. Об агрессивной оптимизации слышали? Я до недавнего времени тоже ничего не знал. Но взгляните сюда: http://forum.vingrad.ru/index.php?showtopic=180722&view=findpost&p=1310994. Поэтому и подвисаний нет. Я так думаю.


for (int i = 0; i < 100; i++)
{
    int sum = i + i;
}

Тут никаких сообщений не будет, но тело цикла будет пустым в сборке. Сам цикл оставляют видимо из-за того, что есть такая штука как busy-waiting loops. Хотя, честно говоря, я не очень понимаю зачем это делается — может просто страшно удалить полностью.


Угадайте, откуда это.
Re: ThreadDemo02.zip ошибка в URL
От: Shadedsun  
Дата: 18.09.08 16:57
Оценка:
Ошибка в URL: ThreadDemo02.zip
Хоть бы ктонить подсказал
Re[3]: Почему вытесняется поток?
От: Experimenter Беларусь  
Дата: 20.09.08 15:14
Оценка:
Здравствуйте, Shadedsun, Вы писали:

S>Здравствуйте, Experimenter, Вы писали:


E>>Не совсем уверен, что MySpinWait в Вашем примере выполняет какую-то работу. Об агрессивной оптимизации слышали? Я до недавнего времени тоже ничего не знал. Но взгляните сюда: http://forum.vingrad.ru/index.php?showtopic=180722&amp;view=findpost&amp;p=1310994. Поэтому и подвисаний нет. Я так думаю.


S>

S>

S>for (int i = 0; i < 100; i++)
S>{
S>    int sum = i + i;
S>}
S>

S>Тут никаких сообщений не будет, но тело цикла будет пустым в сборке. Сам цикл оставляют видимо из-за того, что есть такая штука как busy-waiting loops. Хотя, честно говоря, я не очень понимаю зачем это делается — может просто страшно удалить полностью.


S>Угадайте, откуда это.


В том же топике, немного выше:

S>Про статью:

S>
S>1. Перечисления. Автор двоечник и мерил скорость выполнения пустого цикла, компилер выкидывает такое тело, в этом может убедиться каждый, S>воспользовавшись рефлектором. Я на месте компилера ещё бы и сам цикл выкидывал. Даже если автор отключил оптимизацию, то джитер всё равно тело S>цикла выкинет:
S>

http://www.interface.ru/home.asp?artId=7747 — это ссылка на статью, которая обсуждалась.

Пустые циклы не рулят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.