2013-01-25 32 views
5

Tôi đang trong quá trình cập nhật một ứng dụng Delphi từ Indy 9 đến Indy 10Chuyển từ Indy 9-10 với Delphi, TIdSchedulerOfThreadPool khởi

Nó khá đau đớn, như có vẻ rất nhiều đã thay đổi.

Tôi bị kẹt ở một bước.

Đây là mã cũ (làm việc với Indy 9):

Một Pool Chủ đề được tạo ra và mỗi chủ đề của hồ bơi được khởi tạo và sau đó bắt đầu. Các chủ đề riêng lẻ tạo một máy khách http không hoạt động (nhưng nó không quan trọng ở đây).

TUrlThread = class(TIdThread) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdThreadMgrPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.GetThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
     Priority := Options.Priority; 
     Start; 
    end; 
    end; 

Các TIdThreadMgrPool lớp đã biến mất với Indy 10

Tôi đã nhìn cho một sự thay thế và TIdSchedulerOfThreadPool trông giống như một người chiến thắng, nhưng tôi không thể làm cho nó chạy.

Đây là sửa đổi (Indy 10) mã:

TUrlThread = class(TIdThreadWithTask) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdSchedulerOfThreadPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.NewThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
     Priority := Options.Priority; 
     Start; 
    end; 
    end; 

tôi nhận được một ngoại lệ vi phạm truy cập ở đây (đây là mã indy):

procedure TIdTask.DoBeforeRun; 
begin 
    FBeforeRunDone := True; 
    BeforeRun; 
end; 

FBeforeRunDone là con số không.

Trả lời

7

Bạn chính xác rằng TIdSchedulerOfThreadPool là sự thay thế của Indy 10 cho TIdThreadMgrPool. Tuy nhiên, những gì bạn không tính đến là kiến ​​trúc TIdScheduler hơi khác một chút so với kiến ​​trúc TIdThreadMgr.

Trong Indy 10, TIdThreadWithTask không tự hoạt động. Như tên gọi của nó, TIdThreadWithTask thực hiện một Tác vụ, là đối tượng được nhập TIdTask được nhập trước (chẳng hạn như TIdContext, là thay thế của Indy 10 cho TIdPeerThread) được liên kết với chuỗi. Bạn đang chạy các chủ đề mà không cung cấp cho họ các tác vụ để thực hiện, đó là lý do tại sao bạn gặp phải sự cố. Để gọi Start() theo cách thủ công, trước tiên bạn cần tạo và gán đối tượng dựa trên TIdTask cho thuộc tính TIdThreadWithTask.Task. TIdTCPServer xử lý đó bằng cách gọi TIdScheduler.AcquireYarn() để tạo ra một đối tượng TIdYarn được liên kết đến một đối tượng TIdThreadWithTask, sau đó tạo ra một đối tượng TIdContext và vượt qua nó để TIdScheduler.StartYarn(), trong đó sử dụng các TIdYarn để truy cập TIdThreadWithTask gán tài sản Task của nó trước sau đó gọi Start() trên đó.

Tuy nhiên, tất cả đều không bị mất. Trong cả hai Indy 9 và 10, bạn thực sự không nên gọi TIdThread.Start() theo cách thủ công để bắt đầu. TIdTCPServer xử lý cho bạn sau khi chấp nhận kết nối máy khách mới, lấy chuỗi từ số ThreadMgr/Scheduler và kết nối kết nối máy khách với luồng. Bạn có thể khởi tạo các thuộc tính luồng của mình khi cần mà không thực sự chạy các luồng ngay lập tức. Các thuộc tính sẽ có hiệu lực vào lần đầu tiên các luồng bắt đầu chạy sau đó.

Hãy thử điều này:

TUrlThread = class(TIdThread) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdThreadMgrPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 
    Pool.ThreadPriority := Options.Priority; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.GetThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
    end; 
    end; 

.

TUrlThread = class(TIdThreadWithTask) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdSchedulerOfThreadPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 
    Pool.ThreadPriority := Options.Priority; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.NewThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
    end; 
    end; 

Bây giờ, với điều đó đã nói, một điều cuối cùng cần chú ý. Trong cả hai Indy 9 và 10, có thể cho các chủ đề không được đưa trở lại trong hồ bơi khi hoàn thành, và cho các chủ đề mới để có được thêm vào hồ bơi sau khi mã khởi tạo của bạn đã chạy. Các PoolSize là số lượng tối thiểu của chủ đề để giữ trong hồ bơi, không phải là một số tuyệt đối. Hơn PoolSize số lượng khách hàng có thể kết nối với máy chủ và nó sẽ vui vẻ tạo thêm chủ đề cho họ tại thời điểm chúng cần thiết, do đó bỏ qua mã khởi tạo của bạn. Trong cả hai phiên bản, nơi tốt nhất để sinh lời cho chủ đề của bạn là trong phương thức khởi tạo TUrlThread. Lưu trữ con trỏ Controler của bạn ở đâu đó mà hàm tạo có thể tiếp cận khi cần. Và nó không có ý nghĩa để chỉ định một Index cho mỗi chủ đề vì thứ tự của các chủ đề trong hồ bơi thay đổi động theo thời gian.

Thực tế, mã khởi tạo thủ công của bạn thực sự là sự chấp thuận sai trong cả hai phiên bản vì một lý do khác. Cả hai TIdThreadMgrPool.GetThread()TIdSchedulerOfThreadPool.NewThread() không thêm chủ đề mới vào hồ bơi. Chủ đề được thêm vào hồ bơi trong cả hai Indy 9 và 10 khi một chủ đề ngừng chạy và có chỗ để lưu các chủ đề để tái sử dụng, và bổ sung trong Indy 10 chỉ khi TIdTCPServer là bắt đầu lên. Vì vậy, bạn đang thực sự tạo ra các chủ đề mà không thực sự làm bất cứ điều gì và không được theo dõi bởi các hồ bơi. Tất cả các lý do khác để thiết kế lại mã khởi tạo của bạn trong cả hai phiên bản để chủ đề khởi tạo chính nó khi chúng được tạo trong điều kiện bình thường, thay vì bạn xâm nhập vào kiến ​​trúc để tạo chúng theo cách thủ công.

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