2009-04-14 19 views
33

Tôi đã nhìn thấy thiết lập chung cho việc truy cập luồng chéo vào điều khiển GUI, chẳng hạn như được thảo luận tại đây: Shortest way to write a thread-safe access method to a windows forms controlCó gì sai khi gọi Invoke, bất kể InvokeRequired là gì?

Tất cả các lần truy cập web tôi tìm thấy mô tả một điều tương tự.

Tuy nhiên, tại sao chúng ta cần phải kiểm tra InvokeRequired? Chúng ta có thể gọi Invoke trực tiếp không?

Tôi cho rằng câu trả lời là không, vì vậy câu hỏi thực sự của tôi là 'tại sao'?

Trả lời

28

Từ chủ đề không phải giao diện người dùng, chúng tôi không thể chạm vào giao diện người dùng - những điều rất xấu có thể xảy ra, vì các điều khiển có mối quan hệ chuỗi. Vì vậy, từ một chủ đề không phải UI, chúng ta phải (ở mức tối thiểu) gọi Invoke hoặc BeginInvoke. Tuy nhiên,

Đối với chuỗi giao diện người dùng - chúng tôi không muốn gọi Invoke nhiều thời gian; vấn đề là nếu bạn đã có trên chuỗi giao diện người dùng, nó vẫn có chi phí không cần thiết của việc gửi tin nhắn đến máy bơm của biểu mẫu và xử lý nó.

Trên thực tế, ở hầu hết các mã luồng bạn biết bạn mong đợi một phương pháp cụ thể được gọi là trên một sợi phi -UI, vì vậy trong những trường hợp này, không có chi phí bổ sung: chỉ cần gọi Invoke.

+1

Bạn có biết chúng tôi đang nói chuyện trong bao lâu không? Tôi giả định có một, nhưng tôi đoán nó <0,5 giây, mà trong hầu hết các GUI tôi sẽ nói là chấp nhận được (tho một số có thể không đồng ý) Tôi giả định Control.Invoke không kiểm tra InvokeRequired chính nó vì lý do hiệu suất? – MattH

+1

Ồ, chắc chắn <0.5s - mặc dù bạn có thể thời gian tất nhiên (ví dụ, 10000 cuộc gọi). –

+0

Vì vậy, bạn đang nói rằng 'Invoke()' không tự động kiểm tra 'InvokeRequired' và nội tuyến thực hiện các đại biểu được thông qua chính nó? – binki

2

InvokeRequired về cơ bản sẽ cho bạn biết liệu bạn có đang thực hiện đúng chủ đề hay không. Nếu bạn không phải là chủ đề chính xác, bạn cần phải sắp xếp công việc theo đúng chủ đề nếu không thì không. Do đó sự cần thiết cho việc kiểm tra.

0

Cuộc gọi sẽ gọi mã qua Đại biểu và không trực tiếp sẽ tốn kém.

Chi phí hiệu quả để gọi Chỉ gọi khi được yêu cầu. Do đó, InvokeRequired được sử dụng để tìm ra là cuộc gọi đang được thực hiện từ cùng một chủ đề hoặc chủ đề khác?

+0

Vì nó là cross-threaded, chúng ta sẽ phải gọi Invoke anyway, do đó, các đại biểu là một điều kiện cần thiết mà không thể tránh được. –

+0

Có thể bản chỉnh sửa của tôi sẽ giúp tôi rõ ràng hơn bây giờ. – NileshChauhan

0

Một lý do tôi có thể nghĩ là biểu hiện. Nếu phần lớn thời gian, chuỗi cuộc gọi giống với chuỗi tạo sau đó bạn sẽ có một số phí không chính xác.

1

Vấn đề là các điều khiển GUI có yêu cầu chỉ thực thi mã trên cùng một chuỗi được sử dụng để khởi tạo điều khiển GUI có thể truy cập điều khiển GUI. Những lý do đằng sau yêu cầu này được gắn với cách mà Windows được kiến ​​trúc. Đủ để nói, rất khó để thay đổi điều này.

InvokeRequired kiểm tra danh tính của chuỗi thực thi hiện hành dựa trên danh tính của chuỗi khởi tạo. Nếu chúng giống nhau, mã có thể tự do tương tác với điều khiển. Nếu không, mã phải sắp xếp dữ liệu từ luồng hiện tại đến luồng khởi tạo. Đây là một quá trình chậm và tốn kém và phải tránh nếu có thể. Mã của bạn sẽ hoạt động nếu bạn luôn gọi và nó có thể là bạn sẽ không nhận thấy hiệu suất hit, nhưng kịch bản này sẽ ngày càng phổ biến khi hệ thống đa lõi được đưa vào sử dụng. Tốt nhất là không tạo mã "hải lý" mà phải được hoàn tác sau.

1

Nếu bạn cố gắng gọi trước khi xử lý cửa sổ được tạo (ví dụ: khi gọi hàm tạo biểu mẫu), bạn sẽ nhận được InvalidOperationException. Vì vậy, thường cần kiểm tra InvokeRequired.

Xem MSDN để biết chi tiết.