Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.12.28;
Скачать: [xml.tar.bz2];

Вниз

Посылка строки из TThread в основной поток   Найти похожие ветки 

 
дед Маздай   (2008-11-13 11:30) [0]

Каким образом реализовать сабж? Имеется в виду посылка через SendMessage.
И как реализовать механизм при котором несколько потоков не портили бы посылаемую строку?


 
Сергей М. ©   (2008-11-13 11:36) [1]


> дед Маздай   (13.11.08 11:30)  


А что предполагается делать с переданной строкой в осн.потоке, после того как он ее получит ?


 
Поросенок Винни-Пух ©   (2008-11-13 11:37) [2]

SenMessage(handle,my_message,WParam(PChar(string)),0)


 
дед Маздай   (2008-11-13 11:50) [3]

Сергей М. © (13.11.08 11:36) [1]

Предполагается выводить ее как информацию о работе потока. Например, "Значение 1: 1  -  Значение 2: 2  -  Значение 3: 3" и т.п.


 
Сергей М. ©   (2008-11-13 11:54) [4]


> дед Маздай   (13.11.08 11:50) [3]


А "тормозить" работу доп.потока при этом обязательно ?
Ведь SendMessage - функция, предполагающая синхронное блокирующее исполнение, в отличие от, например, PostMessage ..


 
дед Маздай   (2008-11-13 11:59) [5]

Поросенок Винни-Пух © (13.11.08 11:37) [2]

Да, действительно раборает. А я все пытался указатель передать, типа integer(@somestr) ну и конечно это не работало.


 
дед Маздай   (2008-11-13 12:05) [6]

Сергей М. © (13.11.08 11:54) [4]

Нет, не обязательно. Да я, собственно, нигде этого и не утвеждал. ;)


 
Юрий Зотов ©   (2008-11-13 12:24) [7]

> дед Маздай   (13.11.08 11:59) [5]

1. Можно и проще - Integer(SomeStr). В Delphi переменная типа String - это по сути указатель и его значение можно передавать, как целое число.

2. Если тормозить поток не надо, используйте PostMesage.


 
дед Маздай   (2008-11-13 12:47) [8]

Юрий Зотов © (13.11.08 12:24) [7]

Спасибо, Юрий за расжевывание.


 
Поросенок Винни-Пух ©   (2008-11-13 13:05) [9]

с постом стремно. строка на момент обработки сообщения может быть уже мертва


 
дед Маздай   (2008-11-13 13:38) [10]

Да? Действительно? Я думал об этом, ведь не случано же появилась вторая часть вопроса в [0]


 
Ega23 ©   (2008-11-13 13:48) [11]


> с постом стремно. строка на момент обработки сообщения может
> быть уже мертва


Если она не локальная переменная, то с фига-ли?
Хотя надо смотреть, как реаллок работает...


 
Юрий Зотов ©   (2008-11-13 14:03) [12]

> дед Маздай   (13.11.08 11:30)  

> как реализовать механизм при котором несколько потоков не портили бы
> посылаемую строку?

Потокозащищенный список строк (очередь). Пришедшая строка добавляется в конец списка, а на обработку извлекается первая строка в списке (и после обработки из списка удаляется).

Тогда и сообщений никаких не надо - каждый поток просто добавляет свою строку в список, а главный (или какой-то еще) поток извлекает их оттуда, обрабатывает и удаляет. Кстати, и строки гарантированно не будут умирать раньше, чем будут обработаны.

То есть, надо создать обычный StringList и два потокозащищенных метода - AddString и RemoveString.


 
Ega23 ©   (2008-11-13 14:11) [13]


> То есть, надо создать обычный StringList и два потокозащищенных
> метода - AddString и RemoveString.


тогда уж PushString и PopString, как это в FIFO принято...


 
дед Маздай   (2008-11-13 14:31) [14]

Ага, спасибо. Реализую тогда в таком виде.


 
дед Маздай   (2008-11-13 14:48) [15]

Хотя, если я правильно понимаю, при SendMessage строа не сможет затереться, ведь пока не будет обработано сообщение мы в поток не вернемся, точнее не продолжится работа потока.

На самом деле, это не реальная задача. Я просто изучаю работу с потоками. С синхронизацией через Sinchronize разобрался. Теперь вот через посылку сообщений делал, но видимо задачу не правильно подобрал, т.к эта, конечно же, решается проще именно через Sinchronize.

Есть ли где-нибудь, типа задачника что-то, про потоки, что бы порешать?

Но с очередью всеравно сделаю ;)


 
Ega23 ©   (2008-11-13 15:20) [16]

Очередь "событий" реализуй.


 
Palladin ©   (2008-11-13 15:25) [17]


> тогда уж PushString и PopString, как это в FIFO принято.
> ..

то бишь PUSH и POP принципиально неверно названны? :)


 
Leonid Troyanovsky ©   (2008-11-13 18:07) [18]


> дед Маздай   (13.11.08 11:50) [3]

> Предполагается выводить ее как информацию о работе потока.
>  Например, "Значение 1: 1  -  Значение 2: 2  -  Значение
> 3: 3"

SendMessage(StaticText.Handle, WM_SETTEXT, 0, LParam(PChar("Значение 1: 1")));

{StaticText.AutoSize := False}

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2008-11-13 18:16) [19]


> дед Маздай   (13.11.08 14:48) [15]

> Есть ли где-нибудь, типа задачника что-то, про потоки, что
> бы порешать?

Мануалы знаю, задачники - нет.
Хочешь, дам нетривиальную задачу?
Заодно и поучишься.

> Но с очередью всеравно сделаю ;)

See also TThreadList.

--
Regards, LVT.


 
дед Маздай   (2008-11-13 19:10) [20]

> Leonid Troyanovsky ©   (13.11.08 18:07) [18]
> SendMessage(StaticText.Handle, WM_SETTEXT, 0, LParam(PChar("Значение 1: 1")));

Да, можно и так. Не подумал.


> Leonid Troyanovsky ©   (13.11.08 18:16) [19]
> See also TThreadList.

Надо посмотреть. Незнал. Уже начал вот так:

 TQueueStrings = class(TStringList)
 
 private
   CriticalSectionData: TRTLCriticalSection;
 public
   function AddString(Str: string): Integer;
   procedure RemoveString;
   constructor Create;
   destructor Destroy; override;
 end;

var
 QueueStrings: TQueueStrings;

implementation

constructor TQueueStrings.Create;
begin
 inherited;
 InitializeCriticalSection(CriticalSectionData);
end;

destructor TQueueStrings.Destroy;
begin
 DeleteCriticalSection(CriticalSectionData);
 inherited;
end;

function TQueueStrings.AddString(Str: string): Integer;
begin
 EnterCriticalSection(CriticalSectionData);
 Result := inherited Add(Str);
 LeaveCriticalSection(CriticalSectionData);
end;

procedure TQueueStrings.RemoveString;
begin
 EnterCriticalSection(CriticalSectionData);
 inherited Delete(Count - 1);
 LeaveCriticalSection(CriticalSectionData);
end;

Правда, пока только набрасал, не проверяя, нету дома Дельфей.


> Leonid Troyanovsky ©   (13.11.08 18:16) [19]
> Хочешь, дам нетривиальную задачу?
> Заодно и поучишься.

Хочу =)
Только, боюсь что-либо обещать, т.к. тема новая.


 
Leonid Troyanovsky ©   (2008-11-13 21:58) [21]


> дед Маздай   (13.11.08 19:10) [20]

> procedure TQueueStrings.RemoveString;
> begin
>  EnterCriticalSection(CriticalSectionData);
>  inherited Delete(Count - 1);
>  LeaveCriticalSection(CriticalSectionData);
> end;

> Правда, пока только набрасал, не проверяя, нету дома Дельфей.

Когда будешь проверять не забудь учесть, что
LeaveCriticalSection(CriticalSectionData); почти всегда
д.б. в секции finally.

> Только, боюсь что-либо обещать, т.к. тема новая.

А чего там боятся? Это ж учебная тревога :)

Вот, слушай:

Критическая секция предназначена для синхронизации потоков
одного процесса.
Объет mutex предназначен для аналогичных целей, но может
служить и для потоков разных процессов.  В отличие от критической
секции - это объект ядра, и в случае занятости мьютекса, ожидающий
его поток перейдет из user mode в kernell mode.

Как построить такой  объект синхронизации, который будучи
составлен из "неядерных" объектов (т.е., не Event, Mutex, Semaphor), сможет обслуживать потоки разных процессов?
Эффектом повторного захвата потоком КС(мьютекса) можно пренебречь.

Нужны хинты?
Если - да, то наперво надо искать книгу Джефри Рихтера:
Windows для профи.

--
Regards, LVT.


 
дед Маздай   (2008-11-13 22:59) [22]

> Leonid Troyanovsky ©   (13.11.08 21:58) [21]

Леонид, Вы, видимо, хотите, чтобы я голову себе сломал =) Я только дошел до критических секций, про мьютекы и семафоры читал, т.е. примерно представляю себе как они работают, но сам еще не пробовал. А обучение у меня без практики (просто по книжкам) не идет вообще, мне обязательно надо самому попробовать, что бы отложилось.
А Вы мне тут такое =)
Первые два абзаца я понял, т.к. читал про это, а вот третий... =) Я его раз десять прочел... Всё, что я понял, это то, что надо сделать некое средство, типа мьютекса/семафора, но не используя оных, т.е. своими силами.
...
Прошло 10 минут...
И как же его сделать? Он же должен быть на уровне системы. Он должен быть глобальным для всех процессов.
Хм...
Я с трудом представляю себе эти механизмы.

P.S.
Видимо ночью я не засну =)


 
Leonid Troyanovsky ©   (2008-11-13 23:21) [23]


> дед Маздай   (13.11.08 22:59) [22]

> Видимо ночью я не засну =)

Ну, а книгу Джефа нашел?
Тогда, ночь не пройдет зря :)

--
Regards, LVT.


 
дед Маздай ©   (2008-11-13 23:37) [24]


> Leonid Troyanovsky ©   (13.11.08 23:21) [23]
> Ну, а книгу Джефа нашел?

Нашел. Она у меня была, еще в марте 2007 скачана. Но с экрана читать глаза устают. Надо в субботу в магазин сходить посмотреть. У нас на Измайловском есть прекрасный магазин.


 
Leonid Troyanovsky ©   (2008-11-14 00:05) [25]


> дед Маздай   (13.11.08 22:59) [22]

>  что надо сделать некое средство, типа мьютекса/семафора,
>  но не используя оных, т.е. своими силами.

Хинт 2, от Джефа:
http://msdn.microsoft.com/en-us/magazine/cc302329.aspx

в самом низу, хотя и остальное полезно читать.

>  У нас на Измайловском есть прекрасный магазин.

В книге есть интересная статья про SWMRG (single writer -
multiply readers guardian object). Проясняет многое про
работу мьютексов, событий и семафоров.

Хотя, в самом (составном) объекте присутствуют некотрые
неописанные особенности.

--
Regards, LVT.


 
Германн ©   (2008-11-14 00:43) [26]

Ликбез на уроне Рихтера. Это что-то новенькое!
:)


> P.S.
> Видимо ночью я не засну =)
>


> Ну, а книгу Джефа нашел?
> Тогда, ночь не пройдет зря :)
>

Лично я прекрасно бы заснул, впервые читая Рихтера, ночью!


 
дед Маздай ©   (2008-11-14 23:34) [27]


> Leonid Troyanovsky ©   (13.11.08 21:58) [21]
> Вот, слушай:

Завтра схожу попробую купить книжку и посмотрю, что можно с этой задачей сделать. Хотя, если честно, не представляю как это можно замутить. Меня больше смущает тот момент, что объект должен быть глобальным, а реализацию такой штуки я себе просто не представляю.
Кстати, хочу еще книгу Антона Григорьева подкупить.

============

А пока пробовал решить задачу описанную в Юрий Зотов ©   (13.11.08 14:03) [12], но чёй-то застрял. Вот что у меня получилось:

unit Unit1;
...
procedure TForm1.WMUpdateProgess1(var msg: TMessage);
begin
 ProgressBar1.Position := msg.WParam;
 SetCaption(Label1);
end;

procedure TForm1.WMUpdateProgess2(var msg: TMessage);
begin
 ProgressBar2.Position := msg.WParam;
 SetCaption(Label2);
end;

procedure TForm1.SetCaption(aLabel: TLabel);
begin
 if QueueStrings <> nil then begin
  aLabel.Caption := QueueStrings.Strings[0];
  QueueStrings.RemoveString;
 end;
end;

-----------

unit Unit2;
...
 TQueueStrings = class(TStringList)
 private
   qsCriticalSectionData: TRTLCriticalSection;
 public
   function AddString(Str: string): Integer;
   procedure RemoveString;
   constructor Create;
   destructor Destroy; override;
 end;
...
implementation
...

procedure TMyThread.Execute;
var
 I: Integer;
begin
 FreeOnTerminate := True;
 for I := 0 to MaxProgress do begin
   sleep(10);

   if QueueStrings <> nil then begin
     QueueStrings.AddString("Значение: " + IntToStr(i));
     PostMessage(Form1.Handle, FMessage, i, 0);
   end;

   if Terminated then
     Break;
 end;
end;

...
constructor TQueueStrings.Create;
begin
 inherited;
 InitializeCriticalSection(qsCriticalSectionData);
end;

destructor TQueueStrings.Destroy;
begin
 DeleteCriticalSection(qsCriticalSectionData);
 inherited;
end;

function TQueueStrings.AddString(Str: string): Integer;
begin
 EnterCriticalSection(qsCriticalSectionData);
 try
   Result := inherited Add(Str);
 finally
   LeaveCriticalSection(qsCriticalSectionData);
 end;
end;

procedure TQueueStrings.RemoveString;
begin
 EnterCriticalSection(qsCriticalSectionData);
 try
   inherited Delete(0);
 finally
   LeaveCriticalSection(qsCriticalSectionData);
 end;
end;


В общем-то всё работает, за исключением одной маленькой детали. Если честно, я на нее сегодня пол дня убил (подходами минут по 20 с часовыми перерывами =)), но так и не смог побороть. Может направит меня кто на путь истинный? Проблема в том, что в SetCaption мы можем попасть из любого потока (в данном случае их 2) и там начинаются глюки связанные с тем, что значения предназначенные для первого потока иногда (очень редко) печатает второй и наоборот. Пробовал вставлять критическую сессию, но никокого эффекта.


 
Юрий Зотов ©   (2008-11-15 10:19) [28]

> значения предназначенные для первого потока...

В такой реализации строки НЕ предназначены ни для первого, ни для второго потока. Они предназначены для ГЛАВНОГО потока. Поскольку выбирает их из списка и обрабатывает именно главный поток, а оба дополнительных только помещают их в список и шлют уведомление главному.

> иногда (очень редко) печатает второй и наоборот.

В такой реализации ни первый, ни второй поток строки НЕ печатает. Их печатает ГЛАВНЫЙ поток (в чем и состоит обработка). Причем печатает он ВСЕ строки, независимо от их потока-источника.

======================

Два метода WMUpdateProgess здесь не нужны, достаточно одного. Вот смотрите, что получается.

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

2. Строки в общий список заносятся асинхронно и тоже могут быть произвольно перемешаны. Причем совсем не обязательно, что порядок строк в списке соответствует порядку сообщений в очереди. Например:
- первый поток записал строку и его квант кончился;
- второй поток получил управление, записал строку и послал сообщение;
- первый поток снова получил управление и послал сообщение о ранее записанной строке.

3. Выбрав из очереди сообщение, главный поток берет первую строку в списке и выводит ее в Label, соответствующий источнику сообщения. Но сама-то первая строка, которая в этот Label выводится - она ведь может быть от ЛЮБОГО источника. Совсем не обязательно от того, в чей Label она выводится. Получается как раз то, что Вы и наблюдаете.

====================

Поэтому два метода WMUpdateProgess (и два разных сообщения) здесь не нужны, достаточно одного общего. Введя два сообщения Вы, по сути, идентифицировали их источники (кстати - почему не через LParam?) - а идентифицировать нужно СТРОКИ, а не сообщения. Потому что:
"порядок строк в списке совсем не обязательно соответствует порядку сообщений в очереди".

Эта фраза - ключевая. Если она будет понята и прочно усвоена, то в дальнейшем работа с потоками не будет представлять затруднений.

Чего Вам и желаю.
:о)


 
Leonid Troyanovsky ©   (2008-11-15 12:22) [29]


> дед Маздай ©   (14.11.08 23:34) [27]

> А пока пробовал решить задачу описанную в Юрий Зотов ©  
>  (13.11.08 14:03) [12], но чёй-то застрял. Вот что у меня
> получилось:

Назначение представленного объекта - работа в GUI приложении,
причем вторичные потоки только добавляют строки,
а обрабатываются они в первичном.

Обработку естественно представить так:

захват КС
try
 while (Count > 0) do
    begin
       DoSomething;
       Delete(0);
    end;
finally
 освобождение КС
end;

Т.е., пока в списке что-то есть первичный поток обрабатывает очередь,
а вторичные ждут освобождения КС.

Начинать обработку первичный будет в районе Application.OnIdle.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2008-11-15 12:36) [30]


> дед Маздай ©   (14.11.08 23:34) [27]

> procedure TQueueStrings.RemoveString;
..
>    inherited Delete(0);

inherited - здесь лишнее.

--
Regards, LVT.


 
дед Маздай ©   (2008-11-16 00:54) [31]

> Юрий Зотов ©   (15.11.08 10:19) [28]

Осознал и усвоил =)
Огромное, человеческое спасибо!
Очень помог в осознании пункт 2. Я этого не понимал.

Сделал одно сообщение (всмылсе для обоих потоков) и передаю данные непосредственно в строке, потом разбираю и печатаю в нужный Label.


> (кстати - почему не через LParam?)

А что, это критично? Просто раньше там чего-то тоже посылалось, а потом так и оставил.


> Leonid Troyanovsky ©   (15.11.08 12:22) [29]
> Т.е., пока в списке что-то есть первичный поток обрабатывает
> очередь, а вторичные ждут освобождения КС.

Как раз этого "а вторичные ждут" я хотел избежать. Хотелось, чтобы потоки не останавливались и работали независимо от вывода информации.


> Leonid Troyanovsky ©   (15.11.08 12:36) [30]
> inherited - здесь лишнее.

Почему? Верю, конечно, на слово, но...

P.S.
Ходил сегодня в магазин. Нету у них Рихтера =( Купил только Григорьева. Сказали звонить на неделе, они там, типа, пошукают и если будет то куплю.
Посмотрел по инет магазинам - нет ни в одном =(
Начну пока читать в электронном виде.


 
Германн ©   (2008-11-16 00:59) [32]


> > (кстати - почему не через LParam?)
>
> А что, это критично? Просто раньше там чего-то тоже посылалось,
>  а потом так и оставил.
>

Имхо, это "отрыжка" прошлых времён.


 
Тын-Дын ©   (2008-11-16 01:30) [33]


> Хотелось, чтобы потоки не останавливались и работали независимо
> от вывода информации.


Тогда нужно логику менять.
Простейший способ - обмениваться не через буферную память, а отсылать строки напрямую в основной поток. Например, через Windows-сообщения, используя PostMessage.
К сожалению, скорость вывода информации в этом случае может превысить возможности системы (слишком много поступающих сообщений в основной поток).


 
Тын-Дын ©   (2008-11-16 01:34) [34]

Кстати, возможна регулировка этого потока сообщений при помощи ещё одного дополнительного потока, который как раз и будет обрабатывать сформированный другими потоками буфер и отправлять в основной поток.
Но и здесь подводный камень - в случае, если очередь будет накапливаться слишком долго, может не хватить оперативной памяти.


 
Leonid Troyanovsky ©   (2008-11-16 13:46) [35]


> дед Маздай ©   (16.11.08 00:54) [31]

> > inherited - здесь лишнее.

> Почему? Верю, конечно, на слово, но...

Потому, что Delete в твоем классе не перекрывался, и
нет разницы TQueueStrings.Delete vs TStringList.Delete.

--
Regards, LVT.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2008.12.28;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.57 MB
Время: 0.005 c
15-1225428082
Snoop
2008-10-31 07:41
2008.12.28
Заказ на программу 2


2-1226824815
NoDt
2008-11-16 11:40
2008.12.28
Как вызвать событие перерисовки формы.


4-1202738807
Unicode
2008-02-11 17:06
2008.12.28
TLogFontW и DrawTextW


15-1225264968
начинающий
2008-10-29 10:22
2008.12.28
TM FilePacker -- есть ли альтернатива, менее стремная?


2-1227185785
snake-as
2008-11-20 15:56
2008.12.28
Как запустить *bat скрипт





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский