Согласно «Что нового в Delphi 2009», есть новые функции отладчика, называемые «обход цепочки ожидания». В нем, в частности, говорится: «Была добавлена функция обхода цепочки ожидания, чтобы помочь вам решить проблемы с конфликтами потоков или взаимоблокировками. Эта функция опирается на средство, добавленное в операционную систему Windows Vista, которое предоставляет отладчику информацию о состоянии ожидания потоков вашего приложения в форма цепочки ожидания. "
Delphi 2009 был выпущен, когда Windows Vista была текущей операционной системой. Исходя из моего опыта, большинство функций, представленных в Vista, также доступны в Windows 7. Однако я не вижу эту функцию нигде в моем Delphi 2009 с помощью установок Delphi XE (все в Windows 7).
Я ищу эту функцию на панели потоков отладчика.
Я ищу обход цепи ожидания в правильном месте?
Действительно ли эта функция доступна только в Windows Vista, а не в Windows 7?
Дэвид М дал хороший и четкий ответ, но я все еще не вижу столбец «Цепочка ожидания» на панели «Потоки». Вот некоторый код.
Основная форма:
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SyncObjs, RanThread;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
Button2: TButton;
Label1: TLabel;
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure ThreadDone(Sender: TObject);
end;
var
Form1: TForm1;
RanGenThread: TRandomizer;
implementation
uses LoadThread;
{$R *.dfm}
{ TForm1 }
procedure TForm1.ThreadDone(Sender: TObject);
begin
RanGenThread.Free;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ListBox1.Sorted := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Thread: TLoader;
begin
ListBox1.Items.Clear;
ListBox1.Sorted := False;
RanGenThread := TRandomizer.Create(True);
RanGenThread.ArraySize := 1000;
Thread := TLoader.Create(True);
with Thread do
begin
RanGenThread.WaitThread := Thread;
FreeOnTerminate := True;
OnTerminate := ThreadDone;
WaitForThread := RanGenThread;
//Use Start in Delphi 2010 or later, where Resume is deprecated
Resume;
end;
RanGenThread.Resume;
end;
initialization
Randomize;
end.
TRandomizer:
unit RanThread;
interface
uses
Classes, Math, SyncObjs;
type
TRandomizer = class(TThread)
private
{ Private declarations }
FArraySize: Integer;
protected
procedure Execute; override;
public
WaitThread: TThread;
RandNumbers: array of Integer;
property ArraySize: Integer read FArraySize write FArraySize;
end;
implementation
uses Main;
procedure TRandomizer.Execute;
var
i: Integer;
LowNum, HighNum: Integer;
RandNum: Integer;
begin
if FArraySize = 0 then
begin
Exit;
end;
SetLength(RandNumbers, FArraySize);
LowNum := Low(RandNumbers);
HighNum := High(RandNumbers);
//initialize the array
for i := LowNum to HighNum do
RandNumbers[i] := -1;
// generate the random order
for i := LowNum to HighNum do
while True do
begin
RandNum := RandomRange(LowNum, HighNum + 1);
if RandNumbers[RandNum] = -1 then
begin
RandNumbers[RandNum] := i + 1;
break;
end; // if
end; // while
WaitThread.WaitFor;
end;
end.
TLoader:
unit LoadThread;
interface
uses
Classes, SyncObjs, Dialogs, SysUtils, RanThread;
type
TLoader = class(TThread)
private
FWaitForThread: TRandomizer;
procedure UpdateList;
{ Private declarations }
protected
procedure Execute; override;
public
property WaitForThread: TRandomizer
read FWaitForThread write FWaitForThread;
end;
implementation
uses Main;
procedure TLoader.UpdateList;
var
i: Integer;
begin
for i := Low(FWaitForThread.RandNumbers) to
High(FWaitForThread.RandNumbers) do
Form1.ListBox1.Items.Add(IntToStr(FWaitForThread.RandNumbers[i]));
end;
procedure TLoader.Execute;
begin
if WaitForThread <> nil then
begin
FWaitForThread.WaitFor;
Synchronize(UpDateList)
end;
end;
end.
Согласно документу обхода цепочки ожидания, с которым связывался Дэвид М, WTC доступен для следующих объектов синхронизации:
- ALPC
- COM
- Критические разделы
- Мьютексы
- SendMessage
- Ожидание операций над процессами и потоками
Мой код ожидает потока, но это TThread, а не непосредственно нить. Этим вечером я изменю свой пример кода, чтобы он зашел в тупик при ожидании Mutex, и посмотрю, не приведет ли это к появлению столбца Wait Chain на панели Thread.
OK. Наконец-то нашел время для следующего теста. Создано приложение, которое стало владельцем Mutex при запуске. Создал рабочий поток, который использовал OpenMutex для получения дескриптора этого Mutex, а затем вызвал WaitForsingleObject (handle, INFINITE). Все еще нет столбца цепочки ожидания на панели потоков.