2013-02-17 18 views
5

tôi xem/sử dụng một số hình thức hay thời trang của mã tất cả các thời gian:NET Gọi Process luồng

public void method1(Object sender, EventArgs args) 
{ 
    if(dataGridView1.InvokeRequired) 
    dataGridView1.Invoke(new EventHandler(method1), null); 
    else 
    // Do something to dataGridView1 
} 

Câu hỏi của tôi là ... gì xảy ra với chủ đề giao diện khi tôi sử dụng Invoke? Nó giống như một ngắt, nơi mà các chủ đề sẽ ngay lập tức đi và thực hiện method1?

+0

Tôi không phải là chuyên gia winapi, nhưng hiểu biết cơ bản của tôi là sử dụng SendMessage hoặc PostMessage để gửi một thông điệp đặc biệt đến chuỗi giao diện người dùng của ứng dụng, sẽ, khi được xử lý, hãy gọi phương thức ủy nhiệm, lần này trong ngữ cảnh của chuỗi giao diện người dùng. Các điều khiển được giới hạn theo chuỗi và bạn không thể thực hiện các thao tác trên chúng từ các luồng khác nhau so với các chủ đề mà chúng được tạo ra. – siride

Trả lời

4

là nó như một ngắt ...

Không, không phải ở tất cả. Không có cách nào an toàn để ngắt một luồng khi nó đang bận thực thi mã. Điều đó gây ra một loại vấn đề đặc biệt khó chịu được gọi là "lỗi tái phạm". Đây là loại lỗi mà các lập trình viên phần mềm chiến đấu khi họ thực hiện các trình xử lý ngắt trên các hệ thống nhúng. Một số nền tảng về điều đó trong this web page.

Chuỗi giao diện người dùng của chương trình giải quyết vấn đề này theo cách khác, nó đóng vai trò của người tiêu dùng trong giải pháp tiêu chuẩn cho Producer-consumer problem. Các thành phần là một hàng đợi an toàn mà nhà sản xuất đăng thông báo lên và một vòng điều phối điều phối trong chuỗi tiêu thụ. Truy xuất thư từ hàng đợi và thực thi trình xử lý tin nhắn được liên kết với thư. Điều này thường được mô tả là "bơm vòng lặp tin nhắn". Nhà sản xuất là hệ điều hành phổ biến nhất, tạo ra các thông điệp cho những thứ như người dùng nhấn một phím hoặc di chuyển chuột. Nhưng nó có thể là bất kỳ mã nào tạo ra các thông điệp, kể cả một chuỗi khác.

Winforms thêm hàng đợi bổ sung vào lược đồ này, hàng đợi gọi. Lưu trữ đối tượng ủy nhiệm mà mã của bạn đã tạo cũng như các đối số bạn đã cung cấp. Bắt đầu/Gọi thêm một mục vào hàng đợi gọi và ghim PostMessage() để cho thread UI biết rằng một cái gì đó cần phải thực hiện.

Nếu chuỗi giao diện người dùng bận đang thực thi mã, hãy nói xử lý sự kiện sơn, sau đó bạn không biết gì về điều này. Nó sẽ không thông báo tin nhắn được đăng cho đến khi nó không hoạt động nữa, vào lại vòng điều phối và gọi GetMessage(). Hoặc nó đã nhàn rỗi, sau đó nó sẽ rất nhanh chóng trả lời tin nhắn. Nó truy xuất mục nhập trong hàng đợi gọi và thực hiện mục tiêu đại biểu.

Trong trường hợp Gọi thay vì BeginInvoke, nó sẽ gọi phương thức Set() của ManualResetEvent trong mục nhập hàng đợi. Mà thread của bạn đang chờ đợi, sau đó nó sẽ tiếp tục thực hiện. Nếu phương thức đại biểu thất bại thì tại thời điểm này, ngoại lệ được nêu ra cũng sẽ được nâng lên trong luồng.

Một số kết luận cơ bản bạn có thể rút ra từ cách nó hoạt động:

  • Làm thế nào nhanh chóng chủ đề của bạn sẽ tiếp tục thực hiện hoàn toàn phụ thuộc vào cách bận rộn thread UI là
  • Nói chung bạn muốn ủng hộ BeginInvoke vì đó ngăn cản sợi nhân của bạn từ chặn
  • Begin/gọi các cuộc gọi sẽ được tự động serialized, lần đầu tiên trong lần đầu ra, không có khóa bổ sung là cần
  • Tuy nhiên, nếu bạn sử dụng BeginInvoke sau đó đại biểu sẽ không chạy cho đến sau này, do đó bạn phải đảm bảo rằng mọi dữ liệu bạn cung cấp cho phương thức đích của đại biểu vẫn hợp lệ vào thời điểm nó chạy. Có thể yêu cầu khóa
  • Sử dụng Gọi thay vì BeginInvoke có thể gây tắc nghẽn. Điều này sẽ xảy ra khi chuỗi giao diện người dùng là không phải là số nhưng đang chờ điều gì đó khác xảy ra. Với một bế tắc được đảm bảo khi có điều gì đó khác đang đợi cho chuỗi của bạn kết thúc. Một lý do khác để ủng hộ BeginInvoke qua Gọi
  • Bạn sẽ gặp sự cố khi gọi nhanh hơn chuỗi giao diện người dùng có thể thực hiện các mục tiêu đại biểu. Chuỗi giao diện người dùng không bao giờ có thể bắt kịp và hàng đợi được gọi tăng lên mà không bị ràng buộc. Dễ dàng nhận thấy điều này, chuỗi giao diện người dùng dừng việc chăm sóc các nhiệm vụ ưu tiên thấp. Trong đó bao gồm vẽ, giao diện người dùng của bạn sẽ trông giống như bị đóng băng
  • Bạn sẽ gặp phải vấn đề lớn khi luồng của bạn đang cố gắng gọi đến biểu mẫu hoặc kiểm soát được xử lý. Điều này thường xảy ra khi người dùng đóng cửa sổ của bạn và bạn cũng không đảm bảo rằng chuỗi công việc đã ngừng chạy. Điều này thường dẫn đến sự cố, ObjectDisposedException là kết quả phổ biến nhất
+0

Nếu bạn làm 'BeginInvok' bạn CÓ phải làm' EndInvoke'? – Andrew

+0

Không, đừng gọi EndInvoke(). Điều đó sẽ giống như gọi Invoke(). Cẩn thận rằng những phương thức này làm * không * làm việc giống như phương thức Begin/Invoke của đại biểu, rất khó hiểu. –

+0

Ah ... rất tốt ... – Andrew

2

Câu trả lời đơn giản là: method1 được gọi trong luồng hiện tại (luồng GUI). Nó khá giống với:

public void method1(Object sender, EventArgs args) 
{ 
    if(dataGridView1.InvokeRequired) 
    method1(); 
    else 
    // Do something to dataGridView1 
} 

Ngoại trừ việc nó cũng thực hiện tất cả các phương pháp trước đó đã được xếp hàng trong điều khiển đầm lầy.

Dưới đây là một số chi tiết giải mã Control.Invoke.

Như được giải thích trên MSDN, Invoke "tìm kiếm chuỗi gốc của kiểm soát cho đến khi tìm thấy điều khiển hoặc biểu mẫu có tay cầm cửa sổ". Hãy gọi điều khiển "cha mẹ" này: marshaler.

Sau đó, Invoke gọi marshaler.MarshaledInvoke cùng với người được ủy quyền để thực thi làm đối số.

Trong MarshaledInvoke, một trong những hoạt động đầu tiên được thực hiện là để kiểm tra xem các thread hiện hành (thread đó đã kêu gọi Invoke cũng giống như các chủ đề gắn liền với tay cầm cửa sổ của marshaler. Nó lưu trữ kết quả vào một biến syncSameThread.

nó enqueues nhiệm vụ mới trong một hàng đợi liên quan đến marshaler.

Sau đó, nếu syncSameThreadtrue nó gọi trong InvokeMarshaledCallbacks mà thực hiện trong thread hiện tất cả các nhiệm vụ trong hàng đợi công việc của dòng điện kiểm soát (ở đây là marshaler).

+0

Bài viết về 'InvokeRequired' có nhiều thông tin hơn về chính sách luồng và gotchas: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx – siride