Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вывести в memo от 00000000 до 11111111 
:(
    Опции темы
Петрович
Дата 26.7.2005, 09:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Ну вот. Не прошло и полгода как я вернулся smile
Цитата(Poseidon @ 22.7.2005, 17:04)
Вот набросал тут немного. Так правильно?

Нет. Увы, ты совершил довольно распространенную ошибку! Эту ошибку впервые я увидел в статье какого-то горе программиста. Жаль что она была прочитана многими.
Суть ошибки в следующем.
Как указано в описании метода Synchronize, тело метода переданного в качестве параметра, выполняется в контексте основного потока программы. Теперь, если посмотреть твой код, то вся работа выполняется в методе MemoAdd. А он, в свою очередь, и был передан как параметр при вызове Synchronize. Следовательно, вся работа будет выполняться в контексте основного потока. Т.е. весь смысл использования дополнительного потока теряется!
На самом деле, вся трудоемкая работа должна выполняться в Execute. А Synchronize вызываться только для доступа к методам и свойствам VCL-компонентов.
Правильный код будет выглядеть так:
Код

...
function IntToBin (Value: integer; Digits: integer): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Digits - 1 do begin
    if Value and (1 shl i) > 0
      then result := '1' + result
      else result := '0' + result;
  end;
end;

type
  TMyThread = class(TThread)
  private
    StrForSave :String;       // поле для передачи параметра в SaveStrToMemo
    procedure SaveStrToMemo;  // метод вызываемый в контексте основного потока
  protected
    procedure Execute; override;
  end;

procedure TMyThread.SaveStrToMemo;
begin
  // минимально необходимые действия выполняемые в контексте основного потока
  Form1.Memo1.Lines.Add(StrForSave);
end;

procedure TMyThread.Execute;
var i :Integer;
begin
  FreeOnTerminate := True;        // дабы TMyThread автоматически уничтожился по завершению
  for i:= 0 to 255 do begin
    StrForSave := IntToBin(i,8);
    Synchronize(SaveStrToMemo);
  end;
end;

//---

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyThread.Create(False);
end;


Это правильный метод, рекомендуемый Borland.

Однако, как всегда не единственный.
Например, есть одна интересная особенность процедуры SendMessage. Дело в том, что эта процедура обеспечивает "синхронный" вызов соответствующей оконной процедуры для обработки посылаемого сообщения. А тонкость в том, что вызов оконной процедуры осуществляется в контексте потока создавшего окно, вне зависимости от контекста потока вызвавшего SendMessage. Обеспечивается это самой Windows. Если же знать что все формы Delphi программа создает в контексте основного потока, то этим можно воспользоваться. Вот что мы можем получить в результате:
Код

const
  WM_MY_AddToMemo = WM_USER + 123;

type
  TForm1 = class(TForm)
    ...
  private
    procedure AddToMemoMessage (var Msg: TMessage); message WM_MY_AddToMemo;
  ...
  end;

...

function ThreadFunc (Param: Integer) :Integer; stdcall;
var
  i :Integer;
  s :String;
begin
  for i:= 0 to 255 do begin
    s := IntToBin(i,8);
    SendMessage(Param,WM_MY_AddToMemo,Integer(pChar(s)),0); // СИНХРОННАЯ посылка сообщения форме
  end;
  Result := 0; // код завершения потока. В даннном случае не используется, только лишь для того что бы Delphi не ругался
end;

procedure TForm1.AddToMemoMessage(var Msg: TMessage);
begin
  Memo1.Lines.Add(pChar(Msg.wParam));
end;

procedure TForm1.Button1Click(Sender: TObject);
var 
  h :Cardinal;
  ThreadId :Cardinal;
begin
  h := CreateThread(nil,128,@ThreadFunc,Pointer(Self.Handle),0,ThreadId);
  CloseHandle(h); // нам не нужен результат работы потока, поэтому сразу закроем его хендл
end;

В данном примере я специально не использовал тип tThread дабы продемонстрировать использование потоков через WinAPI.
Обратите внимание на следующее:
1. Функция потока это именно function которая может возвращать результат. Кроме того, она имеет один параметр, и использует способ передачи параметров stdcall
2. Хендл потока возвращаемый CreateThread должен обязательно закрываться как только становится не нужным. Иначе, будут теряться ресурсы системы, естественно в рамках вашего процесса.

В общем, я затронул лишь один из аспектов многопоточных приложений. Белее подробно, рекомендую ознакомиться со статьей: Многопоточность - как это делается в Дельфи. (Перевод статьи "Martin Harvey. Multithreading - The Delphi Way." сделанный Борисом Новгородовым) Это просто ОТЛИЧНАЯ статья.


Добавлено @ 09:41
Да, кстати. Совсем забыл. Под Delphi, вместо лучше CreateThread использовать BeginThread

Это сообщение отредактировал(а) Girder - 26.7.2005, 16:10


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0386 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.