Cố gắng sử dụng TThreadedQueue (Generics.Collections) trong một chương trình dành cho nhiều nhà sản xuất duy nhất. (Delphi-XE). Ý tưởng là để đẩy các đối tượng vào một hàng đợi và để cho một số luồng công nhân thoát khỏi hàng đợi.TThreadedQueue không có khả năng của nhiều người tiêu dùng?
Nó không hoạt động như mong đợi. Khi hai hoặc nhiều chuỗi công nhân đang gọi PopItem, các vi phạm truy cập được ném từ TThreadedQueue.
Nếu cuộc gọi tới PopItem được đăng với một phần quan trọng, tất cả đều ổn.
Chắc chắn TThreadedQueue sẽ có thể xử lý nhiều người tiêu dùng, vậy tôi có thiếu cái gì đó hoặc đây có phải là lỗi thuần túy trong TThreadedQueue không?
Đây là ví dụ đơn giản để tạo lỗi.
program TestThreadedQueue;
{$APPTYPE CONSOLE}
uses
// FastMM4 in '..\..\..\FastMM4\FastMM4.pas',
Windows,
Messages,
Classes,
SysUtils,
SyncObjs,
Generics.Collections;
type TThreadTaskMsg =
class(TObject)
private
threadID : integer;
threadMsg : string;
public
Constructor Create(ID : integer; const msg : string);
end;
type TThreadReader =
class(TThread)
private
fPopQueue : TThreadedQueue<TObject>;
fSync : TCriticalSection;
fMsg : TThreadTaskMsg;
fException : Exception;
procedure DoSync;
procedure DoHandleException;
public
Constructor Create(popQueue : TThreadedQueue<TObject>;
sync : TCriticalSection);
procedure Execute; override;
end;
Constructor TThreadReader.Create(popQueue : TThreadedQueue<TObject>;
sync : TCriticalSection);
begin
fPopQueue:= popQueue;
fMsg:= nil;
fSync:= sync;
Self.FreeOnTerminate:= FALSE;
fException:= nil;
Inherited Create(FALSE);
end;
procedure TThreadReader.DoSync ;
begin
WriteLn(fMsg.threadMsg + ' ' + IntToStr(fMsg.threadId));
end;
procedure TThreadReader.DoHandleException;
begin
WriteLn('Exception ->' + fException.Message);
end;
procedure TThreadReader.Execute;
var signal : TWaitResult;
begin
NameThreadForDebugging('QueuePop worker');
while not Terminated do
begin
try
{- Calling PopItem can return empty without waittime !? Let other threads in by sleeping. }
Sleep(20);
{- Serializing calls to PopItem works }
if Assigned(fSync) then fSync.Enter;
try
signal:= fPopQueue.PopItem(TObject(fMsg));
finally
if Assigned(fSync) then fSync.Release;
end;
if (signal = wrSignaled) then
begin
try
if Assigned(fMsg) then
begin
fMsg.threadMsg:= '<Thread id :' +IntToStr(Self.threadId) + '>';
fMsg.Free; // We are just dumping the message in this test
//Synchronize(Self.DoSync);
//PostMessage(fParentForm.Handle,WM_TestQueue_Message,Cardinal(fMsg),0);
end;
except
on E:Exception do begin
end;
end;
end;
except
FException:= Exception(ExceptObject);
try
if not (FException is EAbort) then
begin
{Synchronize(} DoHandleException; //);
end;
finally
FException:= nil;
end;
end;
end;
end;
Constructor TThreadTaskMsg.Create(ID : Integer; Const msg : string);
begin
Inherited Create;
threadID:= ID;
threadMsg:= msg;
end;
var
fSync : TCriticalSection;
fThreadQueue : TThreadedQueue<TObject>;
fReaderArr : array[1..4] of TThreadReader;
i : integer;
begin
try
IsMultiThread:= TRUE;
fSync:= TCriticalSection.Create;
fThreadQueue:= TThreadedQueue<TObject>.Create(1024,1,100);
try
{- Calling without fSync throws exceptions when two or more threads calls PopItem
at the same time }
WriteLn('Creating worker threads ...');
for i:= 1 to 4 do fReaderArr[i]:= TThreadReader.Create(fThreadQueue,Nil);
{- Calling with fSync works ! }
//for i:= 1 to 4 do fReaderArr[i]:= TThreadReader.Create(fThreadQueue,fSync);
WriteLn('Init done. Pushing items ...');
for i:= 1 to 100 do fThreadQueue.PushItem(TThreadTaskMsg.Create(i,''));
ReadLn;
finally
for i:= 1 to 4 do fReaderArr[i].Free;
fThreadQueue.Free;
fSync.Free;
end;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
ReadLn;
end;
end;
end.
Cập nhật: Các lỗi trong TMonitor khiến TThreadedQueue sụp đổ là cố định trong Delphi XE2.
Cập nhật 2: Kiểm tra trên nhấn mạnh hàng đợi ở trạng thái trống. Darian Miller thấy rằng nhấn mạnh hàng đợi ở trạng thái đầy đủ, vẫn có thể tái tạo lỗi trong XE2. Lỗi một lần nữa là trong TMonitor. Xem câu trả lời bên dưới để biết thêm thông tin. Và cũng là một liên kết đến QC101114.
Cập nhật 3: Với Delphi XE2-cập nhật 4 đã có một sửa chữa công bố cho TMonitor
rằng sẽ chữa các vấn đề trong TThreadedQueue
. Các thử nghiệm của tôi cho đến nay không thể tái tạo bất kỳ lỗi nào trong TThreadedQueue
nữa. Thử nghiệm nhà sản xuất đơn/nhiều chủ đề tiêu dùng khi hàng đợi trống và đầy. Cũng được thử nghiệm nhiều nhà sản xuất/nhiều người tiêu dùng. Tôi thay đổi các chủ đề của người đọc và các chủ đề của người viết từ 1 đến 100 mà không có bất kỳ trục trặc nào. Nhưng biết lịch sử, tôi dám người khác phá vỡ TMonitor
.
Hi LU RD! Chào mừng bạn đến với StackOverflow. Đây là một câu hỏi hay mà bạn có, nhưng có thể dễ dàng kiểm tra xem mã đã được đăng một chút khác đi hay không. Bạn đã bao gồm một nửa .pas của một biểu mẫu, không có DFM tương ứng, và điều đó khiến chúng tôi khó sao chép và điều tra hơn. Vấn đề dường như không liên quan đến giao diện người dùng, vì vậy có cách nào bạn có thể giảm điều này xuống ứng dụng giao diện điều khiển không? Cảm ơn. –
Mason, ứng dụng bảng điều khiển được thực hiện. –
Các sự cố vẫn còn trong XE2 ... –