2009-03-27 45 views
5

Là một phần của quá trình tự động hóa lớn, chúng tôi đang gọi API của bên thứ ba thực hiện một số dịch vụ gọi điện làm việc trên máy khác. Gần đây, chúng tôi đã phát hiện ra rằng mọi khi máy khác không khả dụng, cuộc gọi API sẽ quay đi đôi khi lên đến 40 phút trong khi cố gắng kết nối với máy chủ từ xa.Sử dụng hợp lý luồng trong C#?

API mà chúng tôi đang sử dụng không cung cấp cách xác định thời gian chờ và chúng tôi không muốn chương trình của chúng tôi chờ đợi lâu như vậy, vì vậy tôi nghĩ rằng chủ đề sẽ là một cách hay để thực thi thời gian chờ. Mã kết quả trông giống như sau:

Thread _thread = new Thread(_caller.CallServices()); 

_thread.Start(); 
_thread.Join(timeout); 

if (_thread.IsAlive) 
{ 
     _thread.Abort(); 
     throw new Exception("Timed-out attempting to connect."); 
} 

Về cơ bản, tôi muốn cho APICall() chạy, nhưng nếu nó vẫn đang diễn ra sau thời gian chờ đã trôi qua, giả sử nó sẽ thất bại, giết nó và di chuyển trên.

Kể từ khi tôi mới đến luồng trong C# và trên runtime .net tôi nghĩ rằng tôi muốn hỏi hai câu hỏi liên quan:

Có/cơ chế thích hợp hơn tốt hơn trong các thư viện .net cho những gì tôi m cố gắng để làm, và có tôi cam kết bất kỳ gotchas luồng trong đó bit mã?

Trả lời

5

Thread.Abort() là một yêu cầu cho thread hủy bỏ, và không đảm bảo rằng nó sẽ làm như vậy một cách kịp thời. Nó cũng được coi là thực hành xấu (nó sẽ ném một thread hủy bỏ ngoại lệ trong thread bị hủy bỏ, nhưng có vẻ như API của bên thứ 3 cung cấp cho bạn không có lựa chọn nào khác. bạn nên ping nó trước khi bạn chuyển điều khiển đến đoạn API bên thứ 3.

Nếu không sử dụng một BackgroundWorker, bạn có thể thiết lập IsBackgroundThread của chủ đề là true, vì vậy nó không giữ cho chương trình của bạn từ chấm dứt.

3

Ý tưởng tồi. Thread.Abort không nhất thiết phải dọn dẹp đống lộn xộn còn lại bởi một cuộc gọi API bị gián đoạn như vậy.

Nếu cuộc gọi tốn kém, hãy xem xét viết một .exe riêng biệt thực hiện cuộc gọi và chuyển đối số đến/từ nó bằng cách sử dụng dòng lệnh hoặc tệp tạm thời. Bạn có thể giết chết một .exe an toàn hơn nhiều so với giết một sợi.

0

nó có thể nhưng không ai có thể nói chắc chắn nếu không có sự hiểu biết về API của bên thứ ba. Việc hủy bỏ chuỗi như vậy có thể khiến thành phần ở trạng thái không hợp lệ nào đó có thể không phải là abl e để phục hồi từ, hoặc có thể nó sẽ không tài nguyên miễn phí mà nó được phân bổ (suy nghĩ - nếu một trong những thói quen của bạn chỉ dừng lại thực hiện một nửa chiều qua. Bạn có thể thực hiện bất kỳ đảm bảo nào về trạng thái chương trình của bạn sẽ ở trong đó không?).

Như Cicil đã đề xuất, bạn nên ping máy chủ trước tiên.

3

Bạn cũng có thể sử dụng đại biểu ... Tạo đại biểu cho phương thức thực hiện công việc, sau đó gọi BeginInvoke trên đại biểu, chuyển qua đối số và hàm gọi lại để xử lý giá trị trả về (nếu bạn muốn) ... Ngay sau khi BeginInvoke bạn có thể chờ đợi một thời gian dành riêng cho các đại biểu asynch để kết thúc, và nếu nó không ở chỗ thời gian quy định, di chuyển trên ...

public delegate [ReturnType] CallerServiceDelegate 
      ([parameter list for_caller.CallService]); 

    CallerServiceDelegate callSvcDel = _caller.CallService; 
    DateTime cutoffDate = DateTime.Now.AddSeconds(timeoutSeconds); 
    IAsyncResult aR = callSvcDel.BeginInvoke([here put parameters], 
              AsynchCallback, null); 
    while (!aR.IsCompleted && DateTime.Now < cutoffDate) 
     Thread.Sleep(500); 
    if (aR.IsCompleted) 
    { 
     ReturnType returnValue = callSvcDel.EndInvoke(aR); 
     // whatever else you need to do to handle success 
    } 
    else 
    { 
     callSvcDel.EndInvoke(aR); 
     // whatever you need to do to handle timeout 
    } 

Chú ý: khi viết AsynchCallback thể được null, vì mã lấy giá trị trả về từ EndInvoke(), nhưng nếu bạn muốn bạn có thể có phương thức CallService() gọi cho đại biểu AsynchCallback và chuyển nó trở về giá trị trả về được instaed ...

+0

Bạn xử lý thời gian chờ như thế nào? Bạn chỉ cần để cho các thành phần tiếp tục cố gắng, cho đến 40 phút, để kết nối với máy chủ bị thiếu? Tôi nghĩ rằng câu hỏi là về cách làm cho thành phần ngừng cố gắng kết nối. – Cybis

+0

Xin lỗi, đã chỉnh sửa để thêm mã mẫu ... câu hỏi thời gian chờ được xử lý bởi DateTime.Now

0

Ứng dụng của bạn có chạy trong một thời gian dài hay ứng dụng chạy theo nhu cầu không? Nếu đó là sau này, cá nhân tôi sẽ xem xét việc sử dụng tùy chọn Thread.Abort(). Mặc dù nó có thể không được mong đợi nhất từ ​​quan điểm của một người theo chủ nghĩa thuần túy (quản lý tài nguyên, v.v.), nó chắc chắn đơn giản để thực hiện và có thể đưa ra dự luật cho cách ứng dụng cụ thể của bạn hoạt động.

Ý tưởng về tệp thực thi riêng biệt có ý nghĩa. Có lẽ một tùy chọn khác là sử dụng AppDomains. Tôi không phải là một chuyên gia trong lĩnh vực này (tôi hoan nghênh tinh chỉnh/chỉnh sửa này), nhưng như tôi hiểu nó, bạn sẽ đặt các cuộc gọi API trong một DLL riêng biệt và tải nó vào một AppDomain riêng biệt. Khi cuộc gọi API kết thúc hoặc bạn phải hủy bỏ nó, bạn có thể dỡ bỏ AppDomain cùng với DLL. Điều này có thể có thêm lợi ích của việc làm sạch tài nguyên mà một Thread.Abort() sẽ không đơn giản.

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