![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Мастера, не могу правильно выйти из потока, делаю: [D5]
Yuraz © (2002-04-01 17:32:00)procedure TTestThread.Execute;
begin
FreeOnTerminate:=true; // как сказанно, для прекращения потока
.....код......
end;
В результате по выходу из программы или повторного использования программы пишется WinError, ошибка 1400
Что доделать? В хелпе больше ничего не нашёл по выходу :(
Набережных С. (2002-04-03 19:35:00) [1]
> Digitman © (03.04.02 18:13)
> Совершенно не так) Не стоит тревожиться)
Закрыто:)
Продолжая твою мысль стоит, наверное, пояснить, что первое обращение к методу, требующему хендл, должно производиться из потока родительского окна. Если, например, в дизайн-режиме установлено Visible = false(а так и сделано у автора вопроса), то необходимо обратиться из основного потока к свойству Handle до того, как это сделает дополнительный поток.
Digitman (2002-04-03 18:13:00) [2]>Набережных С.
Совершенно не так) Не стоит тревожиться)
Мне, возможно, лучше было было бы адресовать реплику-дополнение автору. Просто твое неудачное утверждение о thread-safety методов TMemo могло бы ввергнуть автора в последствии в заблуждение, что и конструктор TMemo с таким же успехом можно вызвать в доп.потоке.
Набережных С. (2002-04-03 17:54:00) [3]
> Suntechnic © (03.04.02 04:04)
Убедил. Я действительно плохо смотрел, зациклился на одном и упустил из виду Count. Однако для одного потока это вполне сработает.
> Digitman © (03.04.02 08:26)
Что с тобой? Перечитай посты. Я говорил именноо добавлении строк. Конструктор, точнее создание окна - совсем другая история. Окно должнобыть создано в том же потоке, что и родительское. Рассматривать иной вариант просто не корректно. Я именно и зациклился на графическом контексте(а он здесь безопасен) и конкретной задаче. А в этой задаче Add пройдет "на ура", если одновременно не писать в Мемо из главного потока, но здесь-то это не делается.
Я чувствую в твоем посту какую-то врождебность. Это так?
> Yuraz © (03.04.02 10:26)
Смотри почту. Комментарии в тексте.
REA (2002-04-03 15:02:00) [4]Когда работал с потоками (особенно в DLL) выяснил, что компоненты Delphi 5 как-то криво устроены (или у меня руки) - не всегда завершают поток (а должны - висло где-то в дебрях компонента на WaitFor), при чем при выходе из приложения ситуация обратная (т.е. если допустим по кнопке "стой" работает, то при выгрузке DLL не работает и наоборот). Никаких вызовов VCL из thread нету.
Перепробовал разные варианты с FreeOnTerminate и Terminated.
Поотом надоело - подстроился под это дело (усыплял поток Suspend и потом уже убивал).
Так вот в Delphi 6 этот код уже не работал. Пришлось переставлять строки местами и делать прочие шаманские пассы.
Сейчас вроде работает.
Yuraz (2002-04-03 10:30:00) [5]//где написанно "случайный текст" код
Сорри, всё разобрался
Yuraz (2002-04-03 10:27:00) [6]Да, пример всего 4 кб в архиве.
Yuraz (2002-04-03 10:26:00) [7]Уважаемые мастера, может возмёте этот самый пример на
http://www.kirov.ru/~yura/delphi/d5_thread_exemple.zip
я сделал всё что советовал Александр (panov © (01.04.02 17:47)) , синхронизация не идёт, вопрос вот в чём,
begin
...
begin
for i:=1 to 1000000 do
begin
if Terminated then break;
// Form1.memo2.add(случайный текст);
Synchronize(Upd1);
end;
end;
...
world_sort;
Synchronize(Upd2);
tL.Assign(Form1.Memo2.Lines);А world_sort сортируем tL.
После сортировки копируем tL.Strings в Form1.Memo2.Lines, но при этом используем снова метод Synchronize:
Synchronize(Upd2);
В Upd1 и Upd2 пишем соответственно:
procedure TTestThread.Upd1;
begin
Form1.memo2.add(случайный текст);
end;
где написанно "случайный текст" код 2 раз повторять?
..сейчас просто не останавливается по окончанию работы, программа состоит из 4 модулей, делал в D5. Без многопоточности работала, но если цикл выставляешь большой, форма не реагирует на мышь (ну это как у всех обычных приложений).
Исправильный вариант можно скинуть на мой e-mail, я опубликую так же на сайте, ссылку здесь сразу бы да, да ещё статью бы на писал, на эту темку, для таких как я :)
Digitman (2002-04-03 08:26:00) [8]>Набережных С.
Аргумент от <Suntechnic> - это раз.
Второе. В данном примере TMemo, конечно, создается не в контексте доп.потока (предположим, что - в контексте основном). Но, если конструктор TMemo (а чем он опаснее, в соответствии с твоими утверждениями, того же метода Lines.Add ?) поместить в доп.поток, то обработчик создаваемого ОС-окна (ассоциированного с Memo) будет в последствии так же вызываться системой в том же доп.потоке. И, представь себе, например, WndProc() этого окна будет вызвана в доп.потоке для обработки WM_PAINT (требуется перерисовка некоторой области окна, скажем, для отрисовки вновь добавленной строки). Обработчик в конечном итоге где-то в своем теле вызовет DrawText(), обращаясь к DC окна. И к этому же DC в этот же момент времени может обратится еще один поток того же процесса или kernel-leve-поток.. вот тебе и "глюк" на поверхность выполз)
dymka (2002-04-03 08:20:00) [9]если есть уверенность, что к элементу VCL доступ будет только из одного потока, то синхронизация ни к чему... при доступе из двух потоков и более нужно вызывать Synchronize дабы не было одновременного обращения к объекту (на самом деле одновременно и не может, если комп однопроцессорный, но возможно ситуация - когда когда отображение потока еще не закончено в VCL, а второй поток просто может завершить свое отображение)...
далее - вызов синхронизации немного ограничивает передачц параметров в основной поток - поэтому лучше использовать более продвинутые методы - критические секции итп...
procedure TTestThread.Execute;
begin
FreeOnTerminate := True;
for i:=1 to 1000000 do
begin
if Terminated then break;
Form1.memo2.add(случайный текст);
end;
end;
Form1.Memo2.Visible:=True;
flag1:=true; // разрешено печатать и в html
world_sort; // это отдельная проц. из др. модуля, сортировка memo2 по алфавиту
end;
должно работать... в своей прогамме при вызове
MyThread.Terminate;
свойство потока Terminated установится в True и поток завершится...
Suntechnic (2002-04-03 04:04:00) [10]>Набережных С. (02.04.02 20:35)
Да вообщем-то аргументы весьма просты и даже глубоко копать не надо. Рассмотрим затронутую тут тему, добавление строки в TMemoMemo1.Lines.Add("Test");Наверное трудно не согласится, что в результате этой операции св-во Count у TStrings должно увеличиться. Т.к. VCL это не потоко безопаснаябиблиотека, а инкремент счётчика это не атомарная операция, то возможна ситуация, что к этому св-ву попытается обратится кто-то другой(скажем тоже с целью увеличить его, добавить ещё одну строку) и последствия будут непредсказуемые. В св-ве Count будет находиться значение, которое не отражает действительного положения вещей и чем всё это закончится можно только догадываться. Заметь, я не влазил в дебри VCL и не просматривал весь код метода Add, а лишь взял то, что на поверхности. А если копнуть глубже, то найдёшь ещё десяток подобных мест.
Набережных С. (2002-04-02 20:35:00) [11]
> Alex Sudakov (02.04.02 19:33)
Аргументируй. Какой глюк, в каком месте. Я что-то не вижу. Может, плохо смотрю? И, кстати, вчем видится оригинальность?
Alex Sudakov (2002-04-02 19:33:00) [12]Очень оригинально... Вот только вряд ли будет работать при наличии хотя бы двух потоков. При одновременном обращении к свойству объекта будет замечательный глюк...
Набережных С. (2002-04-02 18:44:00) [13].
> Digitman © (02.04.02 18:12)
Да ради Бога! Все методы в конце-концов попадают в SendMessage, что и есть синхронизация. Для меня это тоже сюрприз - никогда не приходило в головку так сделать :)))
Digitman (2002-04-02 18:12:00) [14]>Набережных С.
Это почему же ? Позволь уж полюбопытствовать ...
Набережных С. (2002-04-02 16:43:00) [15]
> panov © (02.04.02 06:46)
Для добавления в TMemo не нужен Synchronize.
Yuraz (2002-04-02 16:32:00) [16]Александр спасибо! Только сел за инет, разбираюсь.
panov (2002-04-02 06:46:00) [17]Из приведенного кода видно, что ты работаешь с объектами в основном потоке из дополнительного.
В таком случае необходимо использовать метод Synchronize:
В Execute пишем:
tL: TStringList; определяем в секциях определения класса TTestThread
begin
...
begin
for i:=1 to 1000000 do
begin
if Terminated then break;
// Form1.memo2.add(случайный текст);
Synchronize(Upd1);
end;
end;
...
world_sort;
Synchronize(Upd2);
А world_sort сортируем tL.
tL.Assign(Form1.Memo2.Lines);
После сортировки копируем tL.Strings в Form1.Memo2.Lines, но при этом используем снова метод Synchronize:
Synchronize(Upd2);
В Upd1 и Upd2 пишем соответственно:
procedure TTestThread.Upd1;
begin
Form1.memo2.add(случайный текст);
end;
procedure TTestThread.Upd2;
begin
Form1.memo2.Lines.Assign(tL);
end;
В конструкторе класса пишем
Inherited Create(True);
tL := TStringList.Create;
FreeOnTerminate := True;
Resume;
В деструкторе, соответственно
tL.Free;
При необходимости запуска потока:
TTestThread.Create(True); // с параметрами, определенными у тебя.
Все должно работать.
Смысл изменений в том, что из отдельного потока работать с объектами, определенными в основном потоке, нужно через защищенные методы, например, через Synchronize.
Набережных С. (2002-04-01 20:49:00) [18]Насчет Synchronize не обращай внимания, разобрался, мне просто не случалось так делать.
Набережных С. (2002-04-01 20:18:00) [19]
> Form1.memo2.add(случайный текст);
Что, вот так прям и написано, без Synchronize? Или просто сократил? А ОС, видимо, 9х? Поставь в OnCloseQuery главной формы TestThread.Terminate.
Yuraz (2002-04-01 18:41:00) [20]PS,
world_sort; // это отдельная проц. из др. модуля, сортировка memo2 по алфавиту
без неё так же не останавливается, т.е. дело не в ней :)