2008-11-20 17 views
7

Tôi đã bị cắn bởi một giải pháp kiến ​​trúc kém. Nó không phải là chủ đề an toàn!Làm thế nào để sử dụng một AppDomain để giới hạn phạm vi của một lớp tĩnh để sử dụng thread-safe?

Tôi có một số lớp học và thành viên được chia sẻ trong giải pháp, và trong quá trình phát triển tất cả đều ...
BizTalk đã đánh chìm tàu ​​chiến của tôi.

Chúng tôi đang sử dụng Bộ điều hợp BizTalk tùy chỉnh để gọi cho hội đồng của tôi. Bộ điều hợp đang gọi mã của tôi và chạy mọi thứ song song, vì vậy tôi cho rằng nó đang sử dụng nhiều luồng tất cả trong cùng một AppDomain.

Điều tôi muốn làm là làm cho mã của tôi chạy dưới AppDomain riêng của nó để các vấn đề được chia sẻ mà tôi có sẽ không muck với nhau.

Tôi có một lớp rất đơn giản mà bộ điều hợp BizTalk là instantiating sau đó chạy một phương thức Process().

Tôi muốn tạo một AppDomain mới bên trong phương thức Process() của tôi, vì vậy mỗi khi BizTalk quay một luồng khác, nó sẽ có phiên bản riêng của các lớp và phương thức tĩnh.

BizTalkAdapter Code:

// this is inside the BizTalkAdapter and it is calling the Loader class // 
    private void SendMessage(IBaseMessage message, TransactionalTransmitProperties properties) 
    { 

     Stream strm = message.BodyPart.GetOriginalDataStream(); 
     string connectionString = properties.ConnectionString; 
     string msgFileName = message.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties") as string; 


     Loader loader = new Loader(strm, msgFileName, connectionString); 
     loader.Process(); 

     EventLog.WriteEntry("Loader", "Successfully processed: " + msgFileName); 

    } 

Đây là lớp BizTalk cuộc gọi:

public class Loader 
{ 

    private string connectionString; 
    private string fileName; 
    private Stream stream; 
    private DataFile dataFile; 

    public Loader(Stream stream, string fileName, string connectionString) 
    { 
     this.connectionString = connectionString; 
     this.fileName = fileName; 
     this.stream = stream; 
    } 

    public void Process() 
    { 

     //***** Create AppDomain HERE ***** 
     // run following code entirely under that domain 
     dataFile = new DataFile(aredStream, fileName, connectionString); 
     dataFile.ParseFile(); 
     dataFile.Save(); 
     // get rid of the AppDomain here... 

    } 

} 

FYI: Lớp Loader là trong một DLL riêng biệt từ lớp datafile.

Mọi trợ giúp sẽ được đánh giá cao. Tôi sẽ tiếp tục làm việc để tạo mã Thread-Safe, nhưng tôi cảm thấy như thế này có thể là câu trả lời "đơn giản".

Nếu ai có bất kỳ suy nghĩ khác, vui lòng ném vào.

Cảm ơn bạn,
Keith

Chỉ cần cho đầy đủ.

Tôi nhận thấy rằng nếu tôi đánh dấu bộ chuyển đổi gửi là "Giao hàng đặt hàng" trong hộp thoại "Tùy chọn nâng cao giao thông", tôi có thể tránh các sự cố nhiều chủ đề mà tôi đang gặp phải.

Tôi cho rằng đây là một câu trả lời có thể khác cho vấn đề của tôi, nhưng không nhất thiết phải trả lời câu hỏi.

+0

Vì vậy, bạn không nói về các lớp và đối tượng tĩnh, bạn đang nói về một cá thể đơn lẻ, đúng không? –

Trả lời

3

Sử dụng các lĩnh vực ứng dụng bạn có thể làm một cái gì đó như thế này:

public class Loader 
{ 

    private string connectionString; 
    private string fileName; 
    private Stream stream; 
    private DataFile dataFile; 

    public Loader(Stream stream, string fileName, string connectionString) 
    { 
     this.connectionString = connectionString; 
     this.fileName = fileName; 
     this.stream = stream; 
    } 

    public void Process() 
    { 
     //***** Create AppDomain HERE ***** 
     string threadID = Thread.CurrentThread.ManagedThreadId.ToString(); 
     AppDomain appDomain = AppDomain.CreateDomain(threadID); 

     DataFile dataFile = 
      (DataFile) appDomain.CreateInstanceAndUnwrap(
         "<DataFile AssemblyName>", 
         "DataFile", 
         true, 
         BindingFlags.Default, 
         null, 
         new object[] 
         { 
          aredstream, 
          filename, 
          connectionString 
         }, 
         null, 
         null, 
         null); 
     dataFile.ParseFile(); 
     dataFile.Save(); 

     appDomain.Unload(threadID);  
    } 
} 
+0

Kev, Nếu bạn đang sử dụng threadID làm tên miền, có thể sử dụng lần thứ hai của lớp này bằng cùng một chuỗi tạo cùng một tên miền không? Nếu nó đã làm, hai AppDomains sẽ khác nhau với nhau có cùng tên không? Keith –

+0

Tôi đoán vì bạn đang dỡ miền, nó sẽ ổn thôi. Tĩnh của tôi đang lo lắng về sẽ được GC'ed tại thời điểm đó .. Phải không? –

+0

string threadID = Thread.CurrentThread.ManagedThreadId.ToString(); –

0

Tại sao không chỉ đặt khóa quanh mã bạn muốn thực thi tuần tự? Nó sẽ là một nút cổ chai, nhưng nó sẽ làm việc trong một môi trường đa luồng.

public class Loader 
{ 
    private static object SyncRoot = new object(); 
    private string connectionString; 
    private string fileName; 
    private Stream stream; 
    private DataFile dataFile; 

    public Loader(Stream stream, string fileName, string connectionString) 
    { 
     this.connectionString = connectionString; 
     this.fileName = fileName; 
     this.stream = stream; 
    } 

    public void Process() 
    { 

     lock(SyncRoot) { 
      dataFile = new DataFile(aredStream, fileName, connectionString); 
      dataFile.ParseFile(); 
      dataFile.Save(); 
     } 

    } 

} 
+0

Tôi đã nghĩ về điều đó .. Khóa sẽ khiến các luồng khác phải đợi, nhưng các lớp được chia sẻ không được dọn dẹp. Họ ở xung quanh gây đau đầu. –

3

nào bit, chính xác, đang được một nỗi đau về chủ đề an toàn? Tôi không thể thấy bất kỳ trạng thái tĩnh nào cũng như những người độc thân - và dường như có những đối tượng "mới" thích hợp ... tôi có bị mù không?

Vậy bạn đang thấy triệu chứng gì ...

Câu trả lời của AppDomain sẽ chậm (tương đối). Là một phần của hệ thống được hỗ trợ phần mềm trung gian, điều này có thể là OK (tức là "tương đối" nằm trong cùng một công viên bóng).

Nếu bạn làm có trạng thái tĩnh ở đâu đó, một tùy chọn khác đôi khi hoạt động là [ThreadStatic] - mà thời gian chạy diễn giải là "trường tĩnh này là duy nhất cho mỗi chuỗi". Bạn cần phải cẩn thận với khởi tạo, mặc dù - constructor tĩnh trên thread A có thể gán một trường, nhưng sau đó thread B sẽ thấy một null/0/etc.

+0

Tôi có một số lớp tĩnh bên dưới dataFile, bên trong logic phân tích cú pháp và lưu logic. Tôi sẽ xem xét ThreadStatic này và xem liệu nó có thể giúp ích gì không. Cảm ơn bạn. Keith –

0

Nếu bạn đã chia sẻ các thống kê xung đột với nhau, thì bạn có thể thử thêm thuộc tính [ThreadStatic] vào chúng. Điều này sẽ làm cho chúng cục bộ cho mỗi luồng. Điều đó có thể giải quyết vấn đề của bạn trong ngắn hạn. Một giải pháp chính xác sẽ đơn giản là tìm kiếm các công cụ của bạn để đảm bảo an toàn cho luồng.

0

Chỉ để hoàn thành.

Tôi nhận thấy rằng nếu tôi đánh dấu bộ chuyển đổi gửi là "Giao hàng được sắp xếp" trong hộp thoại "Tùy chọn nâng cao giao thông", tôi có thể tránh được các vấn đề đa luồng mà tôi đang gặp phải.

Tôi cho rằng đây là một câu trả lời có thể khác cho vấn đề của tôi, nhưng không nhất thiết đối với câu hỏi.

0

Tạo và rách tên miền ứng dụng cho mỗi cuộc gọi - Tôi nhận thấy bạn không lo lắng về hiệu suất trên ứng dụng này?

Lý tưởng nhất là bạn nên thay đổi mã được gọi thành luồng an toàn.