Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Очередь в потоке


Автор: Lexicss 28.9.2007, 11:00
Ситуация такова. Есть цикл в потоке, который ждёт и обрабатывает сообщения посланные ему. 
Всё до поры работает нормально, однако когда происходит определённая нагрузка на процессор, то приём сообщений внезапно прекращается. 
Т.е. я вижу что поток жив, но GetMessage просто висит и ждёт сообщений, в то время как я их даже искусственно посылаю этому потоку через PostThreadMessage и результат - истина, а GetMessage тихо и спокойно ждёт. 

Вот функция потока:
Код

function TheFunc(P:Pointer):LongInt; stdcall;
var
  AMessage:tMsg;
  boError : boolean;
begin  
  while GetMessage(AMessage,0,0,0)
  do begin
    case Amessage.message of
     wm_ExitThread:
       begin
        ExitThread(0);
       end;
     wm_Pack: 
       begin
         boError := False;
 try
         if TPack(AMessage.lParam).InstanceSize <>
            TPack.InstanceSize then Continue;
 except
         on EAccessViolation do boError := True;
 end;
         if not boError
         then TPack(AMessage.lParam).SendRecvPack;
       end;
    end; // case
    //DispatchMessage(AMessage);
  end;
  Result:=0;
end;  //TheFunc


Есть догадки о том  - при определённой нагрузке проца, нечто непонятное творится с очередью этого потока. Или может что-то ещё? Вообщем вопрос, почему так? 

Характеристики "машины" где такое наблюдается.
Celeron 2,53 GHz
223 Mb RAM
OS: Windows 2000

Автор: dumb 28.9.2007, 11:10
ты уверен что оно на GetMessage подвисает?
еще момент: надо не просто проверять на ненулевость код возврата GetMessage, но и на ошибку(-1), так как в этом случае ты мусор обрабатываешь.

Автор: Lexicss 28.9.2007, 11:29
Цитата(dumb @ 28.9.2007,  11:10)
ты уверен что оно на GetMessage подвисает?
еще момент: надо не просто проверять на ненулевость код возврата GetMessage, но и на ошибку(-1), так как в этом случае ты мусор обрабатываешь.

Вполне уверен. Отладчик в этом помогает делая останов на вариантах. на скока мне известно, даже если и функция вернёт -1, то он этот результат вернёт и прекратит дожидаться. А здесь она висит и всё. Как будто очередь сообщений пуста. Притом это заметно и невооружённым глазом, т.к. при нормальной работе приходят сообщения раз в 200 милисекунд.

Автор: dumb 28.9.2007, 12:49
Цитата(Lexicss @  28.9.2007,  12:29 Найти цитируемый пост)
Отладчик в этом помогает
отладчик, кстати, помимо помощи в таком деле может и свинью подкладывать. лучше лог в файл сделай на время отладки.

Цитата(Lexicss @  28.9.2007,  12:29 Найти цитируемый пост)
на скока мне известно, даже если и функция вернёт -1, то он этот результат вернёт и прекратит дожидаться. А здесь она висит и всё.
возможно, -1 она вернула в предыдущий раз. а на следущий просто "опухла"... хотя это все из области фантастики imho. smile

попробуй использовать http://msdn2.microsoft.com/en-us/library/ms644956.aspx, http://msdn2.microsoft.com/en-us/library/ms644940.aspx...

Автор: Lexicss 28.9.2007, 14:42
Цитата(dumb @  28.9.2007,  12:49 Найти цитируемый пост)
возможно, -1 она вернула в предыдущий раз. а на следущий просто "опухла"... хотя это все из области фантастики imho.

Хорошо, как мне тогда можно проверить эту ситуацию? GetMessage ведь выдаёт булевое значение, и соответсвенно при попытке сравнить её с -1 компилтор выдаёт ошибку Incompatible types.

Автор: Alix 28.9.2007, 14:57
Из MSDN:
Цитата

Because the return value can be nonzero, zero, or -1, avoid code like this:

Код

while (GetMessage( lpMsg, hWnd, 0, 0)) ...

The possibility of a -1 return value means that such code can lead to fatal application errors. Instead, use code like this:
Код

BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}


Цитата
Хорошо, как мне тогда можно проверить эту ситуацию?

Код

  hRetInt := integer(hRetBool);

Особо обращаю внимание на то, что тип BOOL описан как LongBool поэтому integer(bool(-1)) вернет -1. А если так сделать применительно к типу boolean, то результат может быть 1, 127 и 255, в зависимости от того как использовать.

PS: чтобы не быть голословным:
Код
procedure TForm1.Button1Click(Sender: TObject);
var
  x : integer;  // а если объявить как shortint то два последних showmessage'a будут 255
  b : boolean;

begin
  x := -1;
  b := boolean(x);

  showmessage(inttostr(integer(boolean(-1))));
  showmessage(inttostr(integer(boolean(x))));
  showmessage(inttostr(integer(b)));
end;

Автор: Lexicss 28.9.2007, 16:30
Спасиб за инфу.
Однако всё ж проблема остаётся в силе. 
-1 не появляется, а GetQueueStatus ничем не помогает.
Что же всё-таки это может быть(по видимому, тут что-то на уровне системы с формированием очереди).

Есть ещё один инетерсный аспект:  в другой системе(Win 98) эта же операция работала нормально и при загрузке процессора.

Автор: Alexeis 28.9.2007, 16:49
Похоже не неправильную работу с потоками. Т.е. не отработаны все исходы. Например при особых условиях возникает какой-нибудь дедлок. Например если нужно захватить 2 ресурса одновременно и это пытаются сделать 2 потока, каждый успел взять только по одному и ждет пока освободиться другой. Вероятность низкая, но меняется в зависимости от внешних условий.

Добавлено через 6 минут и 20 секунд
Например строка TPack(AMessage.lParam).SendRecvPack; 

 Видно, что lParam - содержит адрес объекта чужего потока, при этом доступ к общим данным никак не синхронизируется, это легко может повлечь самые разные последствия.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)