BeOS Playing

The way i get play with BeOS ...

Saturday, March 12, 2005

 

Залипание

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

Представим себе ГиперМега полезную программу, которая, например, читает\пишет какие-то файлы. Играясь, по ходу написания программы, в основном сосредоточившись на алгортме обработки, был написан для него ГУИ интерфейс. Как запустить алгоритм ?, - допустим кнопкой. Например алгоритм - СделатьПолезное. Хорошо если данные маленькие, а если большие ? Тут вы скажете, что это всего-лишь 2% случаев, и доводку можно списать на суппорт или как исправление багов. Но именно это всегда причина того что как говорят неискушенные "виндовс залипает". Все потому, что люди не понимают что такое потоки и их важность. Или увидели в книге "используйте потоки осторожно" и боятся их юзать. Чужь. Юзать нужно почти всегда и везде.

Допустим у нас жесткие условия, чем сложнее алгоритм - тем он проще. Как заставить писать в потоковом режиме используя буферизацию писать в разные места на диске большие объемы данных ? Очень просто - while (true) printf("xxxxxxxxxxxxx"); Вы себе не представляете какая махина за этим стоит - очереди, Interrupt Request Packets, семиуровневая подель шины драйверов, многопоточные драйвера файловой системы, буферизация. Вообщем не будем изобретать велосипед, а заюзаем эту махину, все равно ничего круче чем в NT не видел. Это и будет наш алгоритм - СделатьПолезное. В первом приближении, представьте себе, что это конвертор AVI.

using System;
using System.IO;
using System.Windows.Forms;
using System.Threading;

public class ГиперМега : Form {
public void УбийцаВремени() {
StreamWriter Полезное = new StreamWriter("ТутЛежитПолезное");
while (true) Полезное.Write("Буратина был тупой ");
}
public void ПередайДальше(object sender, EventArgs e) {
Controls[0].Enabled = false;
УбийцаВремени();
}
public ГиперМега() {
Text = "УльтраСупер";
Button батон = new Button();
батон.Text = "Поджигай";
батон.Click += new EventHandler(ПередайДальше);
Controls.Add(батон);
}
public static void Main() {
ГиперМега СуперУльтра = new ГиперМега();
Application.Run(СуперУльтра);
}
}

Ну вот и написали нашу чудную программу. Хочу вас попросить что бы вы компилировали ее как консольную, почему увидите позже. Поджигаем. И сразу пробуем переместить окошко. Получилось ? Хрен. Почему ? Потому что наш алгоритм СделатьПолезное превратился в УбийцуВремени. Заблокировал поток в котом рисуется ON_PAINT а также где обрабатываются все другие сообщения. Нажмите ^C в консоли. На крест не поможет. За 10 секунд эта прога создст у вас около 50 МБ. Вообщем .NET в этом плане молодец.

А представите теперь что это обычный обработчик кнопки на который вы используете какое-то чужое АПИ, например ходите в базу, или еще какой-то. Вы уверены, что "там" не дойдет до while (true) ? В большенстве случаев как раз именно и на этом "залипают" все проги.

"I шо його робити дорога редакція?". Да всего лишь вынести в поток обработчик.

using System;
using System.IO;
using System.Windows.Forms;
using System.Threading;

public class ГиперМега : Form {
Thread Worker;
public void СделатьПолезное() {
StreamWriter Полезное = new StreamWriter("ТутЛежитПолезное");
while (true) { Полезное.Write("Буратина был тупой "); }
}
public void ПередайДальше(object sender, EventArgs e) {
Controls[0].Enabled = false;
Worker = new Thread(new ThreadStart(СделатьПолезное));
Worker.Start();
}
public ГиперМега() {
Text = "УльтраСупер";
Button батон = new Button();
батон.Text = "Поджигай";
батон.Click += new EventHandler(ПередайДальше);
Controls.Add(батон);
}
protected override void OnClosed(EventArgs e) {
Worker.Abort(); // освободите ресурс
}
public static void Main() {
Application.Run(new ГиперМега());
}
}

И делайте это как можно чаще. И что все обработчики кнопок выносить в отдельные потоки? Я отвечу. Дело в том что архитектура винды не разделяет окно на два потока, один который реагирует на внутренние сообщения, а другой на сообщения пользователя. От этого вся ерунда. Поэтому каждому програмимсту надо изобретать велосипед от "залипания". Можете например в гугле поискать "Worker Controller UI Thread" там написано как нужно разделять оконные и пользовательские потоки в .NET.

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

Добавлю, что во-первых, из-за того, что в BeOS для каждой формы отдельный ГИУ поток (он называется picasso), она ведетсебя так мягко. И инвалидных регионов закрашеных белым вы там никогда не увидите. Даже если запустить 1000 программ, все равно все будем мягко, с каждым разом все медленне и медленне но все будет плавно. А описаных выше проблем там нет. Во вторых люди которые писали приложения для BeOS не ленились нигде проверять количество процессоров в системе и исходя из этого создавать количество потоков. Согласитесь, для большинства, кто пишет под виндовс и в голову такое не придет. Вообщем, тема - многопоточная культура =)

Comments:
Все правильно, но надо ThreadPool.QueueUserWorkItem
 
Post a Comment

Subscribe to Post Comments [Atom]





<< Home

Archives

January 2005   February 2005   March 2005   May 2005   August 2005   February 2006   June 2006   May 2007  

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]