2013-03-25 29 views
6

Tôi đang gặp sự cố với đa luồng trong delphi. Tôi có một danh sách các tên (khoảng 2.000 tên), và tôi cần lấy một số dữ liệu của mỗi tên trong trang của tôi. Hệ thống của tôi hoạt động hoàn hảo, ngoại trừ điều khiển luồng.Đa chủ đề Delphi

Tôi muốn tạo 10 chuỗi và khi một số chuỗi chấm dứt, hãy tạo một chuỗi khác ... cho đến khi kết thúc danh sách.

var 
Form1: TForm; 
tCount: Integer; //threads count 

implementation 

type 
TCheck = class(TThread) 
public 
    constructor Create(Name: string); 
    destructor Destroy; Override; 
protected 
    procedure Execute; Override; 
end; 

MainT = class(TThread) 
protected 
    procedure Execute; Override; 
end; 

destructor TCheck.Destroy; 
begin 
Dec(tCount); 
end; 

procedure MainT.Execute; 
var 
i: Integer; 
Load: TStringList; 
begin 
Load:=TStringList.Create; 
Load.LoadFromFile('C:\mynames.txt'); 

for i:= 0 to Load.Count -1 do 
begin 

    if tCount = 10 then //if we have 10 threads running... 
    begin 
    repeat 
    Sleep(1); 
    until tCount < 10; 
    end; 

    TCheck.Create(Load.Strings[i]); 
    TCheck.Start; 
    Inc(tCount); 

end; 

end; // end of procedure 

Vâng, tôi không đặt TCheck.Constructor vì vấn đề là phương pháp cách tôi kiểm tra số lượng chuỗi đã tạo. Ý tôi là, phần mềm của tôi chỉ dừng lại mà không có bất kỳ thông báo lỗi nào, đôi khi kiểm tra 500 tên, đôi khi 150 tên ...

Xin lỗi vì Bad English.

+0

Bạn có thể đăng câu hỏi về TCheck ctor không? –

+5

Ngoài ra, nếu bạn muốn 10 chủ đề, tạo 10 chủ đề và yêu cầu họ xử lý tất cả công việc của bạn bằng cách xếp hàng cho họ. Không liên tục tạo/chấm dứt/tiêu diệt chúng. Hãy quên đi các chủ đề tCount và vi quản lý. –

+2

Vâng. Bạn cần một nhà sản xuất làm đầy hàng đợi trên luồng và 10 người tiêu dùng tiêu hao nó. –

Trả lời

3

đây là một giải pháp xếp hàng theo chủ đề sử dụng Generics.

Xác định số lượng người tiêu dùng đọc bạn muốn, độ sâu hàng đợi và chỉ chạy thủ tục DoSomeJob từ một chuỗi.

Xác định công việc của bạn làm việc với một chuỗi làm thủ tục chung (trong CaptureJob).

Khi hàng đợi trống, chuỗi tiêu thụ sẽ bị hủy. Thủ tục DoSomeJob đợi cho đến khi tất cả công việc đã sẵn sàng. Bạn có thể dễ dàng biến điều này thành một nhóm nhân viên chung, sử dụng lại các chủ đề mà không phá hủy chúng. Cấu trúc chung của các mục công việc cũng làm cho chúng phù hợp để xử lý các loại công việc khác nhau.

Lưu ý hàng đợi này hoạt động trên XE2 trở lên. Nếu bạn đang sử dụng phiên bản delphi cũ hơn, hãy tìm hàng đợi an toàn tương tự như đề xuất trong nhận xét.

uses 
    Classes,SyncObjs,Generics.Collections; 

Type 
  TMyConsumerItem = class(TThread) 
  private 
    FQueue : TThreadedQueue<TProc>; 
    FSignal : TCountDownEvent; 
  protected 
    procedure Execute; override; 
  public 
    constructor Create(aQueue : TThreadedQueue<TProc>; aSignal : TCountdownEvent); 
  end; 

constructor TMyConsumerItem.Create(aQueue: TThreadedQueue<TProc>); 
begin 
    Inherited Create(false); 
    Self.FreeOnTerminate := true; 
    FQueue := aQueue; 
    FSignal := aSignal; 
end; 

procedure TMyConsumerItem.Execute; 
var 
    aProc : TProc; 
begin 
    try 
    repeat 
     FQueue.PopItem(aProc); 
     if not Assigned(aProc) then 
     break; // Drop this thread 
     aProc(); 
    until Terminated; 
    finally 
    FSignal.Signal; 
    end; 
end; 

procedure DoSomeJob(myListItems : TStringList); 
const 
    cThreadCount = 10; 
    cMyQueueDepth = 100; 
var 
    i : Integer; 
    aQueue : TThreadedQueue<TProc>; 
    aCounter : TCountDownEvent; 
    function CaptureJob(const aString : string) : TProc; 
    begin 
    Result := 
     procedure 
     begin 
     // Do some job with aString 
     end; 
    end; 
begin 
    aQueue := TThreadedQueue<TProc>.Create(cMyQueueDepth); 
    aCounter := TCountDownEvent.Create(cThreadCount); 
    try 
    for i := 1 to cThreadCount do 
     TMyConsumerItem.Create(aQueue,aCounter); 
    for i := 0 to myListItems.Count-1 do begin 
     aQueue.PushItem(CaptureJob(myListItems[i])); 
    end; 
    finally 
    for i := 1 to cThreadCount do 
     aQueue.PushItem(nil); 
    aCounter.WaitFor; // Wait for threads to finish 
    aCounter.Free; 
    aQueue.Free; 
    end; 
end; 

NB: Ken giải thích tại sao khởi tạo và bắt đầu đề của bạn là sai. Đề xuất này cho thấy một cấu trúc tốt hơn để xử lý loại vấn đề này theo cách tổng quát hơn.

+0

Điều này không giải thích cách mã của câu hỏi không hoạt động. Cũng không có dấu hiệu nào trong câu hỏi ban đầu về phiên bản của Delphi đang được sử dụng, vì vậy nó không phải là generics rõ ràng là một lựa chọn. (Xem hai đoạn cuối của câu trả lời của tôi ở trên.) :-) (Không downvoting - chỉ để lại một bình luận.) –

+1

@KenWhite, xin lỗi, câu trả lời này chỉ là để hiển thị như thế nào vấn đề này có thể được giải quyết với một cấu trúc tốt hơn. Tất cả các khoản tín dụng cho bạn để phát hiện lỗi trong mã áp phích. –

1

Nếu bạn không khai báo biến để giữ giá trị trả về TCheck.Create, bạn không thể truy cập TCheck.Start (không có trường hợp nào của TCheck bạn có thể sử dụng để truy cập phương thức Start).

Cách thích hợp sẽ được tuyên bố một var Check: TCheck; bên MainT.Execute, và sau đó lưu trữ các giá trị trả về:

Check := TCheck.Create(Load[i]); { See note below } 
Check.Start; 
Inc(tCount); 

LƯU Ý Thuộc tính mặc định của TStringListStrings, do đó bạn không cần phải sử dụng nó . Bạn chỉ có thể truy cập trực tiếp Strings như tôi đã nêu ở trên. Hai dòng tiếp theo là chính xác những điều tương tự (nhưng rõ ràng là một trong ngắn hơn và dễ dàng hơn để gõ):

Load.Strings[i]; 
Load[i]; 

Nếu bạn không muốn giữ một tham chiếu đến TCheck, chỉ cần thay đổi mã của bạn để trở thành một khối with (bao gồm cả begin..end, và không chứa các mã khác trong khối (đây là chỉ cách tôi từng khuyên bạn sử dụng một with):

with TCheck.Create(Load[i]) do 
begin 
    Start; 
    Inc(tCount); 
end; 

với điều đó đang được nói, có những cách tốt hơn bạn có thể làm điều này thay vì tạo/phá hủy tất cả các loại thứ đọc. Như những người khác đã nói, bạn có thể có danh sách 10 chủ đề và xếp hàng công việc cho họ, để mỗi người xử lý một mục từ Load và sau đó quay lại để có một mục khác để xử lý khi hoàn thành và lặp lại cho đến khi danh sách hoàn tất. Thật khó để nói chính xác làm thế nào bạn sẽ làm điều đó, bởi vì điều đó sẽ phụ thuộc vào phiên bản Delphi của bạn. (Có những thư viện có sẵn mà sẽ làm hầu hết công việc cho bạn, như OMNIThreadLibrary, nhưng nó không có sẵn cho một số phiên bản cũ của Delphi. Các phiên bản gần đây của Delphi cũng hỗ trợ TQueueTObjectQueue và một số loại và chức năng khác có thể rất hữu ích.

(Nếu bạn có một câu hỏi khác nhau về làm thế nào để làm điều này trong một hàng đợi với một số hạn chế về chủ đề, mà phải là một câu hỏi mới , không phải cái gì bạn thêm vào thế này.)

Các vấn đề liên quan