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


Автор: DmitryHT 27.9.2007, 16:58
Как узнать состояние потока?

Т.е. как безошибочно определить состояние потока учитывая то, что поток мог быть еще не запущен, либо уже завершен, либо в процессе.


Нужно для того, чтобы определить свободен ли данный поток для запуска.
Код

potok: array[1..5000] of tPotok;
potok[i].Create = ?


p.s. возможно туплю... smile , но не судите строго

Автор: Alix 27.9.2007, 17:02
Возможно, так.
Код

  if Assigned(potok[i]) then  // Assigned(x) = "x <> nil"
    // busy
  else
    // run

Все зависит от того как ты их завершаешь. Как?

Автор: DmitryHT 27.9.2007, 17:12
Цитата

Все зависит от того как ты их завершаешь. Как?


вот так:
Код

potok[i].FreeOnTerminate(True);


Добавлено через 7 минут и 56 секунд
Alix, в твоем случае срабатывает только когда поток еще не запускался.
После первого запуска он становится Assigned даже не смотря на potok[i].FreeOnTerminate(True);

Автор: Rennigth 27.9.2007, 17:40
DmitryHT, 
Вызываешь ZwQuerySystemInformation с параметром SYSTEMPROCESSESANDTHREADSINFORMATION.
Получаем структуру:
Код

  PSYSTEM_THREADS = ^SYSTEM_THREADS;
  SYSTEM_THREADS  = packed record
    KernelTime: LARGE_INTEGER;
    UserTime: LARGE_INTEGER;
    CreateTime: LARGE_INTEGER;
    WaitTime: ULONG;
    StartAddress: Pointer;
    UniqueProcess: DWORD;
    UniqueThread: DWORD;
    Priority: Integer;
    BasePriority: Integer;
    ContextSwitchCount: ULONG;
    State: Longint;
    WaitReason: Longint;
  end;

State и будет состояние потока. Возможные состояния вот:
Цитата

   THREADSTATE_RUNNING = 0x0001,
   THREADSTATE_STOPPED = 0x0002,
   THREADSTATE_FRESH   = 0x0003,
   THREADSTATE_DEAD    = 0x0004,
   THREADSTATE_FROZEN  = 0x0005


P.S. Метод не проверял пока, только теория, но функцию сделаю, т.к. и мне понадобиться smile
P.S.S. мб есть и другой более простое решение. 

Автор: Alix 28.9.2007, 08:20
Цитата
Alix, в твоем случае срабатывает только когда поток еще не запускался.
После первого запуска он становится Assigned даже не смотря на potok[i].FreeOnTerminate(True); 

Да. В моем случае надо в событии OnTerminate делать 
Код
potok[i] := nil; // i - который сейчас завершился

В помощь: http://forum.vingrad.ru/forum/topic-171639.html и еще http://forum.vingrad.ru/forum/topic-60076.html

Автор: Rennigth 28.9.2007, 10:11
DmitryHT, функция:
Код

const

  SYSTEM_PROCESSES_AND_THREADS_INFORMATION = 5;

  NT_STATUS_SUCCESS              = DWord($00000000);
  NT_STATUS_ACCESS_DENIED        = DWord($C0000022);
  NT_STATUS_INFO_LENGTH_MISMATCH = DWord($C0000004);

  ThreadStateInitialized = $0000;
  ThreadStateReady = $0001;
  ThreadStateRunning = $0002;
  ThreadStateStandby = $0003;
  ThreadStateTerminated = $0004;
  ThreadStateWait = $0005;
  ThreadStateTransition = $0006;
  ThreadStateUnknown = $0007;  

type
  PSYSTEM_THREAD_INFORMATION = ^_SYSTEM_THREAD_INFORMATION;
  _SYSTEM_THREAD_INFORMATION  = packed record
    KernelTime: LARGE_INTEGER;
    UserTime: LARGE_INTEGER;
    CreateTime: LARGE_INTEGER;
    WaitTime: ULONG;
    StartAddress: Pointer;
    UniqueProcess: DWORD;
    UniqueThread: DWORD;
    Priority: Integer;
    BasePriority: Integer;
    ContextSwitchCount: ULONG;
    State: Longint;
    WaitReason: Longint;
  end;

  PSYSTEM_PROCESS_INFORMATION = ^_SYSTEM_PROCESS_INFORMATION;
  _SYSTEM_PROCESS_INFORMATION = packed record
    NextOffset: ULONG;
    ThreadCount: ULONG;
    Reserved1: array [0..5] of ULONG;
    CreateTime: FILETIME;
    UserTime: FILETIME;
    KernelTime: FILETIME;
    ModuleNameLength: WORD;
    ModuleNameMaxLength: WORD;
    ModuleName: PWideChar;
    BasePriority: ULONG;
    ProcessID: ULONG;
    InheritedFromUniqueProcessID: ULONG;
    HandleCount: ULONG;
    Reserved2 : array[0..1] of ULONG;
    PeakVirtualSize : ULONG;
    VirtualSize : ULONG;
    PageFaultCount : ULONG;
    PeakWorkingSetSize : ULONG;
    WorkingSetSize : ULONG;
    QuotaPeakPagedPoolUsage : ULONG;
    QuotaPagedPoolUsage : ULONG;
    QuotaPeakNonPagedPoolUsage : ULONG;
    QuotaNonPagedPoolUsage : ULONG;
    PageFileUsage : ULONG;
    PeakPageFileUsage : ULONG;
    PrivatePageCount : ULONG;
    ReadOperationCount : LARGE_INTEGER;
    WriteOperationCount : LARGE_INTEGER;
    OtherOperationCount : LARGE_INTEGER;
    ReadTransferCount : LARGE_INTEGER;
    WriteTransferCount : LARGE_INTEGER;
    OtherTransferCount : LARGE_INTEGER;
    ThreadInfo: array [0..0] of _SYSTEM_THREAD_INFORMATION;
  end;

function ZwQuerySystemInformation(ASystemInformationClass: Cardinal;
  ASystemInformation: Pointer; ASystemInformationLength: Cardinal;
  AReturnLength: PCardinal): Cardinal; stdcall; external 'ntdll.dll';


function GetNativeThreadInfo(AThreadID: DWORD): _SYSTEM_THREAD_INFORMATION;
var
  pSI, pSITemp: PSYSTEM_PROCESS_INFORMATION;
  hProcess: DWORD;
  dwSize: DWORD;
  dwOffSet: DWORD;
  i: Integer;
  lThreadIsFind: Boolean;
begin
  ZeroMemory(@Result, SizeOF(_SYSTEM_THREAD_INFORMATION));
  if AThreadID = 0 then Exit;

  dwSize := 0;
  lThreadIsFind := False;
  
  if ZwQuerySystemInformation(SYSTEM_PROCESSES_AND_THREADS_INFORMATION,
    nil, 0, @dwSize) <> NT_STATUS_INFO_LENGTH_MISMATCH then Exit;  (* Get Size *)

  pSI := VirtualAlloc(nil, dwSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
  if Assigned(pSI) then
  try
    if ZwQuerySystemInformation(SYSTEM_PROCESSES_AND_THREADS_INFORMATION,
      pSI, dwSize, @dwSize) = NT_STATUS_SUCCESS then
    begin
      pSITemp := pSI;
      repeat
        {$RANGECHECKS OFF}
        for i := 0 to pSITemp.ThreadCount - 1 do
        begin
          if pSITemp.ThreadInfo[i].UniqueThread = AThreadID then
          begin
            Result := pSITemp.ThreadInfo[i];
            lThreadIsFind := True;
            Break;
          end;
        end;
        {$RANGECHECKS ON}
        dwOffSet := pSITemp^.NextOffset;
        pSITemp := Pointer(DWORD(pSITemp) + dwOffSet);

        if lThreadIsFind then
          Break;
      until dwOffSet = 0;
    end;
  finally
    VirtualFree(pSI, 0, MEM_RELEASE);
  end;
end;



Использование:
Код

var
  lThreadInfo: _SYSTEM_THREAD_INFORMATION;
begin
  lThreadInfo := GetNativeThreadInfo(GetCurrentThreadId);
  case lThreadInfo.State of
    ThreadStateInitialized: Caption := 'Thread is ThreadStateInitialized';
    ThreadStateReady: Caption := 'Thread is ThreadStateReady';
    ThreadStateRunning: Caption := 'Thread is ThreadStateRunning';
    ThreadStateStandby: Caption := 'Thread is ThreadStateStandby';
    ThreadStateTerminated: Caption := 'Thread is ThreadStateTerminated';
    ThreadStateWait: Caption := 'Thread is ThreadStateWait';
    ThreadStateTransition: Caption := 'Thread is ThreadStateTransition';
    ThreadStateUnknown: Caption := 'Thread is ThreadStateUnknown';
  end;


Функция принимает ID потока. У Tthread есть св-во ThreadID, его и используй в качестве параметра.

Автор: DmitryHT 28.9.2007, 14:28
Цитата

В моем случае надо в событии OnTerminate делат


спасибо помогло ;)

Автор: Delphist 31.10.2007, 12:22
Цитата(Rennigth @  28.9.2007,  11:11 Найти цитируемый пост)
Функция принимает ID потока. У Tthread есть св-во ThreadID, его и используй в качестве параметра

Не очень быстрый вариант приходится перебирать все потоки, мне кажется должна быть готовая API-функция

Автор: Alix 31.10.2007, 12:35
Сделать SuspendThread, если вернула -1, значит был работающим, иначе вернет предыдущее значение thread suspend count. После этой проверки сделать ResumeThread, чтобы вернуть все на место  smile 

Автор: Rennigth 31.10.2007, 13:05
Цитата(Delphist @  31.10.2007,  12:22 Найти цитируемый пост)
мне кажется должна быть готовая API-функция 
 
Готовая какая? По хендлу? Даже если бы такая и была, она действовала по такому же принципу, только еще бы и ID этого потока искала(могу, ошибаться, уж незнаю как сама винда получает доступ к своим системным объктам). Да и тем более если честно немогу придумать случая когда это нужно, если ты знаешь только хендл...
В любом случае, ни по ID, ни по хендлу вроде нету, уж документированной точно. 

Автор: Delphist 31.10.2007, 13:21
Цитата(Alix @  31.10.2007,  13:35 Найти цитируемый пост)
Сделать SuspendThread, если вернула -1, значит был работающим

значит был УЧИЧТОЖЕН, но SuspendThread не позволяет определить был ли поток приостановлен

Автор: Alix 31.10.2007, 13:45
Цитата(Delphist @  31.10.2007,  14:21 Найти цитируемый пост)
значит был УЧИЧТОЖЕН, но SuspendThread не позволяет определить был ли поток приостановлен

извиняюсь, это я обшибся, если работал, то вернет 0, если не существовал, вернет -1, если > 0, то был приостановлен

Автор: Delphist 31.10.2007, 14:08
Цитата(Alix @  31.10.2007,  14:45 Найти цитируемый пост)
извиняюсь, это я обшибся, если работал, то вернет 0, если не существовал, вернет -1, если > 0, то был приостановлен 

Я тут узнал, для того чтобы узнать существует ли поток или нет достаточно использовать GetExitCodeThread

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