2017-02-17 15 views
5

Tôi có một chương trình sử dụng Chủ đề thực hiện một số công việc. Các thread nên thông báo cho một thread (trong ví dụ này là chủ đề chính) của tiến trình.Xử lý biến cục bộ trong quy trình ẩn danh được chuyển đến TThread.Queue

Nếu tôi sử dụng Đồng bộ hóa() để thực hiện đồng bộ hóa mọi thứ hoạt động như mong đợi. Nếu tôi đồng bộ hóa với các chủ đề chính và công bố cho biến và đặt nó vào một danh sách tất cả các giá trị duy nhất có được của in một cách chính xác vào ListBox của tôi:

procedure TWorkerThread.Execute; 
var 
    i: Integer; 
begin 
    inherited; 

    for i := 1 to 1000 do 
    begin 
    Synchronize(
     procedure() 
     begin 
     FireEvent(i); 
     end); 
    end; 
end; 

Output: 1, 2, 3, 4, 5. .. 1000

Nếu tôi sử dụng Queue() để thực hiện việc đồng bộ hóa đầu ra không được như mong đợi:

procedure TWorkerThread.Execute; 
var 
    i: Integer; 
begin 
    inherited; 

    for i := 1 to 1000 do 
    begin 
    Queue(
     procedure() 
     begin 
     FireEvent(i); 
     end); 
    end; 
end; 

Output: 200, 339, 562, 934, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, [...]

gì đang xảy ra ở đây? Theo sự hiểu biết của tôi, thủ tục nặc danh sẽ nắm bắt biến "i"?

+0

PS: Tôi biết nó không có ý nghĩa nhiều khi cập nhật giao diện người dùng này thường xuyên. Tôi chỉ muốn biết điều gì làm cho nội dung biến đổi thay đổi theo phương thức anonymouse nên nắm bắt được giá trị. –

+1

Bạn nắm bắt biến. Nhưng bạn đang cố gắng nắm bắt "giá trị". Vì vậy, bạn cần tạo một biến mới, một biến cho mỗi lần lặp của vòng lặp và nắm bắt được. Điều đó đòi hỏi một khung stack mới, và do đó một cuộc gọi chức năng. Dẫn đến mã trong câu trả lời của LURD. –

Trả lời

5

Quy trình ẩn danh sẽ chụp tham chiếu biến. Điều này có nghĩa là giá trị chưa được xác định khi quy trình ẩn danh chạy.

Để chụp một giá trị, bạn sẽ phải quấn nó vào một khung độc đáo như thế này:

Type 
    TWorkerThread = class (TThread) 
    ... 
    function GetEventProc(ix : Integer): TThreadProcedure; 
    end; 

function TWorkerThread.GetEventProc(ix : Integer) : TThreadProcedure; 
// Each time this function is called, a new frame capturing ix 
// (and its current value) will be produced. 
begin 
    Result := procedure begin FireEvent(ix); end; 
end; 

procedure TWorkerThread.Execute; 
var 
    i: Integer; 
begin 
    inherited; 

    for i := 1 to 1000 do 
    begin 
    Queue(GetEventProc(i)); 
    end; 
end; 

Xem thêm Anonymous methods - variable capture versus value capture.

+0

Điều đó không biên dịch ... –

+0

Nên là 'Hàng đợi (EventWithValue (i))' và 'EventWithValue' sẽ trả về' TThreadProcedure'. Ít nhất, đó là những gì tôi sẽ làm. –

+0

Đọc tài liệu: [Các phương thức ẩn danh trong Delphi] (http://docwiki.embarcadero.com/RADStudio/en/Anonymous_Methods_in_Delphi), đặc biệt là [Biện pháp biến dạng biến danh] [http://docwiki.embarcadero.com/RADStudio/ vi/Anonymous_Methods_in_Delphi # Anonymous_Methods_Variable_Binding). –

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