2013-02-11 23 views
6

Chúng tôi có thư viện đang được WPF và/hoặc máy khách Winform sử dụng.Đồng bộ hóa trên Async tránh bế tắc và ngăn giao diện người dùng bị phản ứng

Chúng tôi đã cung cấp một phương pháp không đồng bộ tương tự như:

Task<int> GetIntAsync() 

Chúng tôi cũng đã (không may) cung cấp một phương pháp wrapper đồng bộ:

int GetInt(); 

mà thực chất chỉ là gọi phương thức không đồng bộ và cuộc gọi .Result về nhiệm vụ của nó. Gần đây, chúng tôi đã nhận ra trong một số trường hợp, một số mã trong số GetIntAsync cần chạy trên luồng giao diện người dùng chính (cần sử dụng thành phần COM cũ được đánh dấu là mô hình Luồng "Đơn" (tức là thành phần phải chạy trong phần chính). STA chủ đề không chỉ là chủ đề bất kì STA)

vì vậy, vấn đề là khi GetInt() được gọi vào các chủ đề chính, nó sẽ bế tắc từ

  • các .Result khối các chủ đề chính,
  • mã trong số GetIntAsync() sử dụng Dispatcher.Invoke để cố gắng chạy trên chuỗi chính.

Phương pháp đồng bộ đã được tiêu thụ nên sẽ là một thay đổi đột phá để xóa nó. Vì vậy, thay vào đó, chúng tôi đã chọn sử dụng WaitWithPumping trong phương thức GetInt() đồng bộ của chúng tôi để cho phép lời gọi đến chuỗi chính hoạt động.

Tính năng này hoạt động tốt ngoại trừ khách hàng sử dụng GetInt() từ mã giao diện người dùng của họ. Trước đây, họ hy vọng rằng việc sử dụng GetInt() sẽ khiến giao diện người dùng của họ không phản hồi - tức là, nếu họ gọi là GetInt() từ bên trong trình xử lý sự kiện nhấp chuột của nút, họ sẽ không có thông báo nào được xử lý cho đến khi trình xử lý trả về. Bây giờ các tin nhắn được bơm, giao diện người dùng của chúng tôi là đáp ứng và nút tương tự đó có thể được nhấp lại (và có thể họ không mã hóa trình xử lý của họ để được tham gia lại).

Nếu có một giải pháp hợp lý, chúng tôi muốn không có khách hàng của chúng tôi cần phải mã hóa chống lại giao diện người dùng được đáp ứng trong một cuộc gọi đến GetInt

Câu hỏi:

  • Có cách để thực hiện WaitWithPumping sẽ bơm thông báo "Gọi đến chính", nhưng không bơm các tin nhắn liên quan đến giao diện người dùng khác?
  • Sẽ đủ cho mục đích của chúng tôi nếu giao diện người dùng của khách hàng hoạt động như thể một hộp thoại phương thức hiện được hiển thị, mặc dù bị ẩn (tức là người dùng không thể truy cập các cửa sổ khác). Nhưng, từ những gì tôi đọc, bạn không thể ẩn một hộp thoại phương thức.
  • Các cách giải quyết khác mà bạn có thể nghĩ đến sẽ được đánh giá cao.

Trả lời

4

Thay vì sử dụng bơm nhắn hiện có, bạn có thể tạo bơm thông điệp của riêng mình trong ngữ cảnh GetInt. Here là một mục blog thảo luận về cách viết một. This is the full solution the blog creates.

Sử dụng mà bạn có thể viết nó như:

public int GetInt() 
{ 
    return AsyncPump.Run(() => GetIntAsync()); 
} 

Điều đó sẽ dẫn đến hoàn toàn ngăn chặn các thread UI như mong đợi, trong khi vẫn đảm bảo rằng tất cả các continuations gọi từ GetIntAsync không bế tắc như họ sẽ được marshaled đến một khác nhau SynchronizationContext. Cũng lưu ý rằng máy bơm thông báo này vẫn đang chạy trên chuỗi STA/UI chính.

+0

Cảm ơn. Tôi thấy khối giao diện người dùng. Không may mã cố gắng để có được các chủ đề chính là sử dụng Dispatcher chủ đề chính 'Dispatcher.Invoke' để có được chủ đề chính. Tôi đoán để thực hiện công việc này tôi sẽ cần phải thay đổi mã đó để sử dụng SynchronizationContext, chứ không phải là Dispatcher của chủ đề chính. Có cách nào để làm cho nó hoạt động với Dispatcher của thread chính không? –

+0

@MattSmith Mã của bạn không hoạt động cụ thể vì bạn đang sử dụng bộ điều phối của chủ đề chính. – Servy

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