Ну вот. Не прошло и полгода как я вернулся 
| Цитата(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 должен обязательно закрываться как только становится не нужным. Иначе, будут теряться ресурсы системы, естественно в рамках вашего процесса.
В общем, я затронул лишь один из аспектов многопоточных приложений. Белее подробно, рекомендую ознакомиться со статьей: http://mbo88.narod.ru/ToC.html Это просто ОТЛИЧНАЯ статья.
Добавлено @ 09:41 Да, кстати. Совсем забыл. Под Delphi, вместо лучше CreateThread использовать BeginThread |