2013-03-11 48 views
10

Tôi vừa "giành được" đặc quyền để duy trì một thư viện kế thừa được mã hóa bằng C# tại công việc hiện tại của tôi.Thực hiện cuộc gọi lắp ráp COM của tôi không đồng bộ

dll này:

  • phơi bày phương pháp cho một hệ thống di sản lớn được thực hiện với Uniface, mà không có lựa chọn nào khác kêu gọi các đối tượng COM.
  • Phục vụ dưới dạng liên kết giữa hệ thống cũ này và API của một hệ thống khác.
  • Sử dụng WinForm cho giao diện người dùng trong một số trường hợp.

trực quan hơn, như tôi hiểu các thành phần:

*[Big legacy system in Uniface]*== [COM] ==>[C# Library]== [Managed API] ==>*[Big EDM Management System]*

Câu hỏi đặt ra là : Một trong những phương pháp trong Thư viện C# này mất quá nhiều thời gian để chạy và tôi "nên" làm cho nó không đồng bộ!

Tôi đã quen với C#, nhưng không được sử dụng COM. Tôi đã thực hiện chương trình đồng thời, nhưng COM dường như thêm nhiều phức tạp cho nó và tất cả các thử nghiệm của tôi cho đến nay kết thúc ở một trong hai:

  • Một vụ tai nạn không có thông báo lỗi nào cả
  • My DLL chỉ một phần đang hoạt động (chỉ hiển thị một phần giao diện người dùng của nó và sau đó đóng), và vẫn không cho tôi bất kỳ lỗi nào tại tất cả

Tôi hết ý tưởng và tài nguyên về cách xử lý các chủ đề trong một dll COM, và tôi sẽ đánh giá cao bất kỳ gợi ý hoặc trợ giúp nào.

Cho đến nay, phần lớn nhất của mã Tôi đã thay đổi để làm cho phương pháp không đồng bộ của tôi:

// my public method called by the external system 
public int ComparedSearch(string application, out string errMsg) { 
    errMsg = ""; 
    try { 
    Action<string> asyncOp = AsyncComparedSearch; 
    asyncOp.BeginInvoke(application, null, null); 
    } catch (ex) { 
    // ... 
    } 
    return 0; 
} 

private int AsyncComparedSearch(string application) { 
    // my actual method doing the work, that was the called method before 
} 

Bất kỳ gợi ý hoặc tài nguyên hữu ích sẽ được đánh giá. Cảm ơn bạn.

UPDATE 1:

Sau câu trả lời và manh mối dưới đây (đặc biệt là về SynchronizationContext, và với sự giúp đỡ của this example) tôi đã có thể cấu trúc lại mã của tôi và làm cho nó để làm việc, nhưng chỉ khi gọi từ khác Ứng dụng cửa sổ trong C# và không thông qua COM. Hệ thống cũ gặp lỗi khá mơ hồ khi tôi gọi hàm và không cung cấp bất kỳ chi tiết nào về sự cố.

UPDATE 2:

cập nhật mới nhất trong các thử nghiệm của tôi: Tôi quản lý để thực hiện các công việc xử lý đa luồng khi các cuộc gọi được thực hiện từ một dự án thử nghiệm, và không từ hệ thống Uniface. Sau nhiều lần thử nghiệm, chúng tôi có xu hướng nghĩ rằng hệ thống cũ của chúng tôi không hỗ trợ đa luồng tốt trong cấu hình hiện tại của nó.Nhưng đó không phải là điểm của câu hỏi nữa :)

Dưới đây là một exerpt của mã điều đó dường như làm việc:

string application; 
SynchronizationContext context; 

// my public method called by the external system 
public int ComparedSearch(string application, out string errMsg) { 
    this.application = application; 
    context = WindowsFormsSynchronizationContext.Current; 
    Thread t = new Thread(new ThreadStart(AsyncComparedSearchAndShowDocs)); 
    t.Start(); 
    errMsg = ""; 
    return 0; 
} 

private void AsyncComparedSearch() { 
    // ANY WORK THAT AS NOTHING TO DO WITH UI 
    context.Send(new SendOrPostCallback(
     delegate(object state) 
     { 
      // METHODS THAT MANAGE UI SOMEHOW 
     } 
    ), null); 
} 

Chúng tôi hiện đang xem xét các giải pháp khác hơn là sửa đổi lắp ráp COM này, như đóng gói này thư viện trong một Dịch vụ Windows và tạo một giao diện giữa hệ thống và dịch vụ. Nó phải bền vững hơn ..

+3

+1 cho câu hỏi được tổ chức tốt này. – 3yanlis1bos

+0

Bạn có thể cung cấp một mẫu thực sự nhỏ sẽ bị hỏng không? Tôi không thực sự chắc chắn những gì chính xác bạn đang làm để làm cho nó sụp đổ :) (Nếu đó là lỗi của bạn, hoặc nếu đó là hệ thống di sản mà không thể xử lý luồng) – Onkelborg

+0

Bạn có nói rằng ngoại lệ là không bao giờ bị bắt hoặc nó không không chứa bất kỳ tin nhắn nào cả? –

Trả lời

2

Thật khó để nói mà không biết thêm chi tiết, nhưng có vài vấn đề ở đây.

Bạn thực hiện ủy quyền trên một chuỗi khác qua BeginInvoke nhưng bạn không đợi. Khối try\catch của bạn sẽ không bắt được bất cứ thứ gì vì nó đã được truyền trong khi cuộc gọi từ xa vẫn đang được thực hiện. Thay vào đó, bạn nên đặt try\catch khối bên trong AsyncComparedSearch.

Khi bạn không đợi đến khi kết thúc việc thực hiện phương thức từ xa (EndInvoke hoặc qua gọi lại), tôi không chắc chắn cách bạn xử lý kết quả của cuộc gọi COM. Tôi đoán sau đó bạn cập nhật GUI từ bên trong AsyncComparedSearch. Nếu vậy, nó là sai, vì nó đang chạy trên một thread khác và bạn sẽ không bao giờ cập nhật GUI từ bất cứ đâu ngoại trừ GUI thread - nó rất có thể sẽ dẫn đến sự cố hoặc hành vi không mong muốn khác. Vì vậy, bạn cần phải đồng bộ hóa công việc cập nhật GUI với chủ đề GUI. Trong WinForms, bạn cần sử dụng Control.BeginInvoke (đừng nhầm lẫn với Delegate.BeginInvoke) hoặc một số cách khác (ví dụ: SynchronizationContext) để đồng bộ hóa mã với luồng GUI. Tôi sử dụng một cái gì đó tương tự như sau:

private delegate void ExecuteActionHandler(Action action); 

public static void ExecuteOnUiThread(this Form form, Action action) 
{ 
    if (form.InvokeRequired) { // we are not on UI thread 
    // Invoke or BeginInvoke, depending on what you need 
    form.Invoke(new ExecuteActionHandler(ExecuteOnUiThread), action); 
    } 
    else { // we are on UI thread so just execute the action 
    action(); 
    } 
} 

sau đó tôi gọi nó là như thế này từ bất kỳ chủ đề:

theForm.ExecuteOnUiThread(() => theForm.SomeMethodWhichUpdatesControls()); 

Bên cạnh đó, đọc this answer đối với một số hãy cẩn thận.

+0

Cảm ơn bạn đã trả lời và liên kết của bạn. Logic trong 'AsyncComparedSearch' khá phức tạp và không phù hợp với bài đăng. Tôi có nhiều khối 'try/catch' trong đó và chúng không bắt được gì cả. Tôi sẽ cố gắng đưa ra các chi tiết quan trọng trong bản chỉnh sửa câu hỏi. Và bạn đúng về xử lý của GUI, điều này được xử lý từ bên trong 'AsyncComparedSearch'. Tôi sẽ tìm kiếm theo hướng đó ngày hôm nay và cho bạn biết. – David

+0

Tôi đã thêm một lưu ý về đồng bộ hóa vào câu trả lời –

+0

Theo các gợi ý được đưa ra trong câu trả lời của bạn và liên kết về 'SynchronizationContext', tôi có thể làm cho chức năng của tôi hoạt động chính xác, nhưng chỉ khi cuộc gọi được thực hiện từ một dự án C# khác, và không phải khi cuộc gọi được thực hiện từ hệ thống kế thừa thông qua COM. Ít nhất, có một sự tiến hóa tích cực ở đây. – David

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