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

Вниз

Мешают ли потоки ловить сообщения   Найти похожие ветки 

 
TUser ©   (2004-05-25 13:04) [0]

В приложении запущен поток, который в некоторый момент оказывается занят таким вот циклом

while FStatus = stWaiting do // FStatus - глобальная переменная в данном юните
  sleep(200);

Там же есть форма, которая ловит массаги. Есть процедуры, типа
procedure WMMine(...); message WM_MINE;
...
procedure WMMine(...);
begin
  MyThread.Status:=stComplete;
end;

Вроде бы такие сообщения должны ловиться. Но они не ловятся (поток свою работу не заканчивает, бряки в обработчиках сообщений ничего не ловят). Посылаются они точно и по правильному хэндлу - в этом я уверен на 100%. Мешает ли работающий поток ловить сообщения окну в данной программе (при учете, что там есть sleep, и вроде бы основному потоку приложения ничего не мешает извлекать сообщения из очереди)? Если да, то как такое можно обойти.

PS. ProcessMessages в потоке пробовал ставить (хотя это и не хорошо), но бестолку.

PPS. Извините, что в Потрепацу, в Основную не добавилось.


 
Polevi ©   (2004-05-25 13:14) [1]

потоки не мешают
а сделано криво у тебя
почитай про объекты синхронизации


 
vuk ©   (2004-05-25 13:16) [2]

А почему бы самому потоку сообщения не ловить?


 
TUser ©   (2004-05-25 13:37) [3]


> А почему бы самому потоку сообщения не ловить?

Разницы никакой.


> почитай про объекты синхронизации

А какие лучше использовать? Я знаю, что бывают семафоры, мьютексы, критические секции пр., но раньше никогда такие штуки не делал. И что они должны синхронизировать? Если я правильно понимаю, эти объекты позволяют исключить одновременный доступ нескольких процессов к ресурсу или более обще - не допустить одновременного выполнения определенного кода. Но здесь, вроде два процесса, каждый со своими ресурсами. Поясните, пож-та, зачем здесь нужны эти объекты.


 
vuk ©   (2004-05-25 13:41) [4]

to TUser ©   (25.05.04 13:37) [3]:
>Разницы никакой.
Да ну? См. MsgWaitForMultipleObjects


 
DiamondShark ©   (2004-05-25 13:43) [5]

А кто сообщения посылает?


 
TUser ©   (2004-05-25 13:45) [6]


> А кто сообщения посылает?

Другая прога. Тоже моя. Посылает SendMessage"ем, хэндл точно правильный, сообщения тоже.


> >Разницы никакой.

Я имел в виду, что при если послать эти сообщения потоку и ему передать обработчики, то ничего не поменялось. Спасибо, иду читать.


 
Тимохов ©   (2004-05-25 13:46) [7]

Соглашусь с [1] - криво у тебя сделано.
Один поток не может мешать другому потоку выбирать сообщения из своей очереди.

Приведи код кто посылает сообщение.

Синхронизация здесь имхо не нужна - устанавливать значение fStatus можно без синхронизации.


 
vuk ©   (2004-05-25 13:51) [8]

Проверка переменной - не очень эффективно, т.к. периодически нужно "будить" поток и проверять, что там происходит. В принципе, в данном случае лучше было бы устроить потоку ожидание события, но можно и при помощи сообщения сделать. :o)


 
TUser ©   (2004-05-25 14:11) [9]


> Приведи код кто посылает сообщение.

Прога 1 посылает WM_COPYDATA проге 2. В обработчике в проге 2, читаем хэндл из WParam, что-то делаем, потом посылаем несколько сообщений в прогу 1. Посылаем через SendMessage на тот хэндл, который прочитали. Пробовал даже на HWND_BROADCAST, то бестолку. Сообщения определены как WM_USER + 100/200/300. Неужели из-за того, что процедура является обработчиком какого-то сообщения, она сама посылать уже не может?

PS. Понял, что надо подботать про синхронизацию процессов. Обязательно займусь на досуге.


 
Тимохов ©   (2004-05-25 14:14) [10]

подботай, но проблема у тебя не в этом :(((


 
DiamondShark ©   (2004-05-25 14:21) [11]


> Неужели из-за того, что процедура является обработчиком
> какого-то сообщения, она сама посылать уже не может?

Угу. Во избежание дедлоков.

Попробуй написать везде вместо

SendMessage(la-la-la)

Win32Check( SendMessage(la-la-la) )


 
Тимохов ©   (2004-05-25 14:24) [12]


> Посылаем через SendMessage на тот хэндл, который прочитали

Просвети откуда ты прочитываешь хэндл.

ЗЫ
Ты бы потрудиля минут 10 на составление полноценного вопроса с необходимым и достаточным кол-вом кода :)))))


 
Digitman ©   (2004-05-25 14:34) [13]


> TUser ©   (25.05.04 13:04)  
> В приложении запущен поток, который в некоторый момент оказывается
> занят таким вот циклом


на здоровье .. какие "занятия" ты потоку дал, тем он и занимается

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

ожидание сообщений - WaitMessage(), MsgWaitForMultipleObjects()

получение сообщений без ожидания - PeekMessage()
получение сообщений с ожиданием - GetMessage()


 
Тимохов ©   (2004-05-25 14:38) [14]


> DiamondShark ©   (25.05.04 14:21) [11]

какие дедлоки? :))
Может я что-то пропустил в своем образовании.

Мой опыт говорит о том, что в обработчике синхронного сообщения ничего не мешает послать синхронное же сообщение автору первого сообщение. Все будет работать.


 
DiamondShark ©   (2004-05-25 14:43) [15]


> Тимохов ©   (25.05.04 14:38) [14]
>
> > DiamondShark ©   (25.05.04 14:21) [11]
>
> какие дедлоки? :))
> Может я что-то пропустил в своем образовании.

If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, Windows switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message.

ЗЫ
С Win32Check я наврал.


 
TUser ©   (2004-05-25 14:49) [16]

2 [12]
ОК. Вот код, вродедолжно хватить. Скажите, как это сделать на основе пересылки сообщений. Сейчас код выглядит так.
Программа-посылатель

unit Unit1;

 ....

 TLooker = class(TThread)
 private
   procedure Put;

   procedure WmStart(var Msg:TMessage); message WM_STARTINFO;
   procedure WmEnd(var Msg:TMessage); message WM_ENDINFO;
   procedure WmCopyData(var Msg:TMessage); message WM_COPYDATA;
   procedure WmFileEnd(var Msg:TMessage); message WM_FILEEND;
 public
   FStatus:(stWaiting, stGettingData, stComplete, stFinished, stNone);
   res:TKister;
   procedure Execute; override;
 end;
 
 TKiller = class(TThread)
 private
 public
   T1, T2:TDateTime;
   procedure Execute; override;
 end;

var
 FEExplorer: TFEExplorer;
 FEWin:hWND;
//  FindEatPath:string;
 Looker:TLooker;
 Killer:TKiller;
 FLength:integer;
 FNextIndex:integer;
 FResult:TResult;
 FPhase:byte;
 FPI:PProcessInformation;

 ...

implementation

procedure Run;
begin
  ... // CreateProcess
end;

procedure TFEExplorer.Button1Click(Sender: TObject);
var cf:string;
begin
  Looker.Resume;
end;

procedure TLooker.Execute;
var cf:string;
   i:integer; deb:integer;
   SA:PSecurityAttributes;
   SI:TSTartUpInfo;
   cd:TCopyDataStruct;
   DOING:boolean;
   d:integer;
begin
  while {not finished} and (not Terminated) do begin
     cf:={file name}

     ...

     Run;

     cd.cbData:=length(cf)+1; cd.lpData:=PChar(cf); cd.dwData:=0;
     SendMessage(HWND_BROADCAST{FEWin},WM_COPYDATA,Handle,LongInt(@cd));
     Killer.Resume;
     repeat
        FStatus:=stWaiting; Killer.T1:=now;
        while FStatus = stWaiting do begin
           sleep(200);
           // Application.ProcessMessages;
           end;
        while (FStatus<>stComplete) and (FStatus<>stFinished) do
           sleep(0);
        if FStatus<>stComplete then
           FStatus:=stNone
           else  ...
     until FStatus = stNone;
     Killer.Suspend;
     DeleteFile(cf);

     end;
end;

procedure TLooker.Put;
var i,j:integer;
begin
 // Печать результатов
end;

procedure TLooker.WmStart(var Msg:TMessage);
begin
  FStatus:=stGettingData;
  FLength:=Msg.LParam;
  setLength(Looker.res.Kisters,FLength);
  setLength(Looker.res.Scores,FLength);
  FNextIndex:=0; FPhase:=0;
  FResult:=krFinished;
  while not ord(FResult) = Msg.WParam do
     inc (FResult);
end;

procedure TLooker.WmEnd(var Msg:TMessage);
begin
  FStatus:=stComplete;
  if FNextIndex<FLength*3 then
     begin end; // do something
end;

procedure TLooker.WmCopyData(var Msg:TMessage);
var cd:PCopyDataStruct;
   s:string;
begin
  if (FStatus = stGettingData) and (FEWin = Msg.WParam) then begin
     cd:=PCopyDataStruct(Msg.LParam);
     if FPhase<4 then
        Looker.res.Kisters[FNextIndex,FPhase]:=PChar(cd.lpData)
        else Looker.res.Scores[FNextIndex]:=Double(cd.lpData^);
     inc(FPhase);
     if FPhase = 5 then begin
        inc(FNextIndex);
        FPhase:=0;
        end;
     end;
end;

procedure TLooker.WmFileEnd(var Msg:TMessage);
begin
  FStatus:=stFinished;
end;

procedure TKiller.Execute;
begin
  while not Terminated do begin
     sleep(2000);
     T2:=now;
     if SecondsBetween(T1,T2) > 5*60 then begin
        // restart
        TerminateProcess(FPI^.hProcess,0);

        Looker.FStatus:=stNone;
        end;
     end;
end;

....


Программао-получатель
procedure SendResults(IsFinishing:boolean; Handle:hWND;Result:TKister);
var i,j:integer; d:double;
   cd:TCopyDataStruct;
begin
   SendMessage({HWND_BROADCAST}Handle,{WM_DONE}WM_STARTINFO,ord(result.Result),result.Size);
   for i:=0 to result.Size-1 do begin
      for j:=0 to 3 do begin
         cd.dwData:=0; cd.cbData:=system.length(result.Kisters[i,j])+1;
         cd.lpData:=PChar(result.Kisters[i,j]);
         SendMessage({HWND_BROADCAST}Handle,WM_COPYDATA,Handle,LongInt(@cd));
         end;
      d:=Scores[i];
      cd.dwData:=0; cd.cbData:=sizeof(Double); cd.lpData:=@d;
      end;
   if IsFinishing then
      SendMessage({HWND_BROADCAST}Handle,WM_ENDINFO,0,0)
      else SendMessage({HWND_BROADCAST}Handle,WM_FILEEND,0,0);
end;

procedure TFindEatWindow.AnalizeFile(var Msg:TMessage);
var FName:PChar;
   result:TKister;
   ic,im:integer; i,j:integer;
   m:TModel;     h:hWND;
   cd:TCopyDataStruct;
   d:double;
begin
  FName:=PChar(PCopyDataStruct(Msg.LParam)^.lpData);
  h:=Msg.WParam;

  if FileExists(FName) then begin
     if assigned(Prot) then begin
        Prot.Free;
        Prot:=nil;
        end;
     Prot:=TProtein.Create;
     try
     with Prot do begin
        FileName:=FName;
        Parse;
        // finding
        for ic:=0 to ChCount-1 do begin
           result.Result:=krUnknownError;
           if Chains[ic].ModCount>0 then begin
              im:=0;
              m:=Chains[ic].Models[im];
              FindBeta(m);
              FindKisters(m);
              result.Result:=krFinished;
              result.Size:=system.length(Pairs);
              setLength(result.Kisters,result.Size);
              setLength(result.Scores,result.Size);
              for i:=0 to result.Size-1 do begin
                 result.Scores[i]:=Scores[i];
                 for j:=0 to 3 do
                    result.Kisters[i,j]:=m.Residues[Pairs[i,j]].ShortName+
                                         inttostr(m.Residues[Pairs[i,j]].Position)+"("+
                                         inttostr(m.Residues[Pairs[i,j]].Number)+")"+
                                         m.Residues[Pairs[i,j]+2].ShortName+
                                         inttostr(m.Residues[Pairs[i,j]+2].Position)+"("+
                                         inttostr(m.Residues[Pairs[i,j]+2].Number)+")";
                 end;
              result.Result:=krFinished;
              end;
           SendResults(ic<chcount-1,h,result);
           end;
        end;


 
TUser ©   (2004-05-25 14:51) [17]


> If the specified window was created by a different thread

Нет, это обычное окно. TForm. Процедура окна д.б. создана.


 
Digitman ©   (2004-05-25 14:53) [18]


> Программао-получатель
> ...   SendMessage


это что за "получатель" такой, который send-ф-цию вызывает ?)


 
Тимохов ©   (2004-05-25 14:56) [19]


> TUser ©   (25.05.04 14:51) [17]

Уважаемый. Вы тут полную ерунду делаете.

Вы хотите, чтобы в поток приходило сообщение? Я тоже хочу, но обычно я для этого очередь выборки сообщений делаю. Каким чудесным образом в TLooker вызовется хоть одно сообщение?

Для этого нужно сделать очередь выборки сообщений (см. в forms по строке поиска peekmessage). К тому же должен быть dispatch.

Я готовы был вам помочь, но сейчас нет - т.к. нужно фактически за вас все переписать. :(((


 
TUser ©   (2004-05-25 14:58) [20]

Это условные названия. Они оба и получают и отсылают сообщения. Только посылатель не ловит сообщения, отправляемые получателем. Можно было бы их назвать "Контроллер" и "Основная программа"


 
Тимохов ©   (2004-05-25 14:59) [21]

Автору.

Если вы хотите именно синхронные сообщения посылать, то нужно делать окно с оконной процедурой. Иначе вы такое сообщение не обработатете. Окно делать можно через AllocateHWnd.

Огномный совет: прочитет 26 главу рихтера изд 4 про очередь сообщение. Очень будет полезно...


 
TUser ©   (2004-05-25 15:02) [22]

Раньше сообщения ловила форма. Точнее тоже не ловила. Переделал в поток после [2]. Тогда это выглядело так. FStatus была глобальной переменной для этого модуля, а обработчики сообщений были описаны в классе TFEExplorer. Соотвественно было написано SendMessahe(FEWin,WM_COPYDATA,FEExplorer.Handle,...)


 
Тимохов ©   (2004-05-25 15:02) [23]


> TUser ©   (25.05.04 14:58) [20]

при чем здесь названия? :))
Где у вас в tlooker получение сообщения?


 
Digitman ©   (2004-05-25 15:03) [24]


> посылатель не ловит сообщения, отправляемые получателем


для того чтобы он, получатель, их "ловил", см. [13]

либо, если GUI-приложение на базе VCL и "ловец" - осн.код.поток, см. Application.Processmessages


 
TUser ©   (2004-05-25 15:03) [25]


> при чем здесь названия? :))

Это я на [18] отвечал. Ваш пост тогда не читал еще.


 
DiamondShark ©   (2004-05-25 15:06) [26]


>  TLooker = class(TThread)
>  private
>    procedure Put;
>
>    procedure WmStart(var Msg:TMessage); message WM_STARTINFO;
>    procedure WmEnd(var Msg:TMessage); message WM_ENDINFO;
>    procedure WmCopyData(var Msg:TMessage); message WM_COPYDATA;
>    procedure WmFileEnd(var Msg:TMessage); message WM_FILEEND;
>  public
>    FStatus:(stWaiting, stGettingData, stComplete, stFinished,
> stNone);
>    res:TKister;
>    procedure Execute; override;
>  end;

А можно объяснить, что тут имелось в виду? Нужто ожидалось, что процедуры Wm* буду вызываться?

Мама моя родная! Тут такое непонимание наворочено, что даже не знаешь, за что браться...

Давай так начнём. Что надо получить? Самыми общими словами.


 
Digitman ©   (2004-05-25 15:19) [27]


> TUser ©   (25.05.04 14:51) [17]


1. Sendmessage(HWND_BROADCAST) не может послать сообщение именно потоку - эта ф-ция предназначена для синхр.посылки сообщений ОКНАМ, которые поток потенциально может создать, вызывая, например, CreateWindow(Ex)

2. Для того чтобы код.поток мог ожидать+выбирать+обрабатывать в некий нужный момент времени сообщения, адресованные ему либо ЕГО ОКНАМ, он должен в нужный момент времени выполнить хотя бы один раз хотя бы следующее :

if GetMessage(Msg, 0, ..) then
 if Msg.hWnd <> 0 then
   begin
     //Translatemessage(Msg); как правило, бессмысленно для неосн.код.потока
     DispatchMessage(Msg); //обработка сообщений, адресованных  ОКНАМ потока
   end
 else
   Dispatch(Msg.message); //обработка сообщений (посланных by PostThreadMessage) САМОМУ потоку как объекту-наследнику TObject


 
TUser ©   (2004-05-25 15:27) [28]

Видать, рано мне такие штуки творить. Сделаю как-нибудь попроще и пойду читать Рихтера и иже с ним.
Всем спасибо.


 
Тимохов ©   (2004-05-25 15:29) [29]


> TUser ©   (25.05.04 15:27) [28]

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


 
Digitman ©   (2004-05-25 15:30) [30]


> пойду читать Рихтера и иже с ним


сие весьма отрадно



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

Форум: "Потрепаться";
Текущий архив: 2004.06.13;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.059 c
6-1082779446
Aplay
2004-04-24 08:04
2004.06.13
мак адрес по ip в сети


1-1085850377
ltexcimer
2004-05-29 21:06
2004.06.13
обработка ошибок


1-1085768409
FuTe
2004-05-28 22:20
2004.06.13
dll


6-1082722632
xman
2004-04-23 16:17
2004.06.13
mailslot already exests


3-1085083852
GanibalLector
2004-05-21 00:10
2004.06.13
IBConsole или альтернатива???





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский