2012-05-17 39 views
5

Tôi có dịch vụ cửa sổ nhiều luồng trong .Net 3.5 và tôi gặp một số sự cố khi dừng dịch vụ đúng cách khi tạo nhiều hơn một luồng.Dừng dịch vụ cửa sổ nhiều luồng

Dịch vụ này được sử dụng để tạo chỉ một chuỗi để thực hiện tất cả công việc và tôi vừa thay đổi nó thành đa luồng. Nó hoạt động hoàn hảo, nhưng khi dịch vụ được dừng lại, nếu có nhiều hơn một luồng đang được thực thi, nó sẽ treo dịch vụ cho đến khi tất cả các luồng được hoàn tất.

Khi dịch vụ được bắt đầu, tôi tạo ra một sợi nền để xử lý các quá trình chính:

protected override void OnStart(string[] args) 
    { 
     try 
     { 
      //Global variable that is checked by threads to learn if service was stopped 
      DeliveryConstant.StopService = false; 
      bool SetMaxThreadsResult = ThreadPool.SetMaxThreads(10, 10); 

      ThreadStart st = new ThreadStart(StartThreadPool); 
      workerThread = new Thread(st); 
      workerThread.IsBackground = true; 
      serviceStarted = true; 
      workerThread.Start(); 
     } 
     catch (Exception ex) 
     { 
      //Log something; 
     } 

Dưới đây là phương pháp StartThreadPool:

//Tried with and without this attribute with no success... 
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] 
    public void StartThreadPool() 
    { 
     while (serviceStarted) 
     { 
      ProcessInfo input = new ProcessInfo(); 

      try 
      { 
       int? NumPendingRequests = GetItems(50, (Guid?)input.ProcessID); 

       if (NumPendingRequests > 0) 
       { 
        input.ProcessType = 1; 
        input.ProcessID = Guid.NewGuid(); 
        ThreadPool.QueueUserWorkItem(new WaitCallback(new DispatchManager().ProcessRequestList), input); 
       } 
      } 
      catch (Exception ex) 
      { 
       //Some Logging here 
      } 
     } 

     DeliveryConstant.StopService = true; 
    } 

Tôi tạo ra một biến tĩnh trong một lớp học riêng biệt để thông báo cho các chủ đề rằng dịch vụ đã bị ngừng. Khi giá trị cho biến này là sự thật, tất cả các chủ đề nên dừng lại vòng lặp chính (một cho mỗi vòng lặp):

 public static bool StopService; 

Cuối cùng, phương pháp OnStop:

protected override void OnStop() 
    { 
     DeliveryConstant.StopService = true; 

     //flag to tell the worker process to stop 
     serviceStarted = false; 

     workerThread.Join(TimeSpan.FromSeconds(30)); 
    } 

Trong phương pháp ProcessRequestList, tại cuối mỗi foreach, tôi kiểm tra giá trị của biến StopService. Nếu đúng, tôi phá vỡ vòng lặp.

Đây là vấn đề: Chủ đề được tạo thành các đoạn 50 mục. Khi tôi có 50 mục hoặc ít hơn trong cơ sở dữ liệu, chỉ có một luồng được tạo và mọi thứ đều hoạt động tốt. Khi tôi có hơn 50 mục, nhiều chuỗi sẽ được tạo và khi tôi cố gắng dừng dịch vụ, nó sẽ không dừng cho đến khi tất cả các chủ đề nền được hoàn thành.

Từ nhật ký, tôi có thể thấy rằng phương thức OnStop chỉ được thực thi SAU KHI tất cả các chuỗi được hoàn tất.

Bất kỳ đầu mối nào có thể được thay đổi để sửa lỗi đó?

+0

Thử đặt chế độ Ngủ (50) trong vòng lặp while. –

+0

Dường như với tôi rằng Bạn chưa bao gồm phần quan trọng nhất của mã. Đó là thực thi phương thức ProcessRequestList. –

+0

Bạn có thể hiển thị mã nơi StopService được thẩm vấn không? Nhìn vào bằng cách sử dụng CancellationToken trên tĩnh var, vì nó được làm cho loại điều đó. – hatchet

Trả lời

9

blog answer tuyên bố rằng OnStop không được gọi cho đến khi tất cả các tác vụ của ThreadPool hoàn tất, đó là tin tức cho tôi nhưng sẽ giải thích vấn đề của bạn.

Tôi đã đưa ra nhiều dịch vụ Windows đa luồng nhưng tôi thích tạo chủ đề nền của riêng mình hơn là sử dụng ThreadPool vì đây là các chuỗi dài. Tôi khởi tạo các lớp nhân viên và khởi chạy phương thức DoWork() của họ trên luồng. Tôi cũng thích sử dụng gọi lại cho lớp khởi chạy để kiểm tra tín hiệu dừng và trạng thái vượt qua thay vì chỉ thử nghiệm với biến toàn cầu.

+0

Bạn đóng đinh chính xác vấn đề. Cảm ơn nhiều! Điều này là khá nhiều những gì tôi nói rằng đã xảy ra, nhưng không biết rằng đó là một hành vi mong đợi. Biết rằng, bây giờ tôi đang kiểm tra trạng thái dịch vụ trong các chuỗi làm việc, và nó hoạt động như một sự quyến rũ. Không chắc chắn (chưa) như thế nào tốn kém nó sẽ được cho hiệu suất mặc dù. Cảm ơn! – Roberto

+0

Roberto, bạn có nhớ gửi giải pháp của mình trong câu hỏi của bạn hay biến bSean StopService là gì? – PAULDAWG

3

Bạn đang thiếu các rào cản bộ nhớ xung quanh quyền truy cập vào StopService, có thể là một vấn đề nếu bạn có nhiều CPU. Khóa tốt hơn bất kỳ đối tượng tham chiếu nào cho TẤT CẢ truy cập vào biến được chia sẻ. Ví dụ:

object @lock; 

... 

lock (@lock) 
{ 
    StopService = true; 
} 

Sửa: Như câu trả lời khác đã tiết lộ, vấn đề này không phải là một vấn đề khóa, nhưng tôi rời khỏi câu trả lời này đây như là một điều cần kiểm tra với các chương trình đồng bộ hóa đa luồng.

Biến biến chia sẻ dễ bay hơi cũng sẽ hoạt động trong nhiều trường hợp, nhưng sẽ phức tạp hơn để chứng minh chính xác vì nó không phát ra hàng rào đầy đủ.

+0

Đây không phải là về nguyên tử nhưng về rào cản bộ nhớ. Nguyên tử có nghĩa là luồng khác sẽ thấy tất cả - hoặc không có gì. Rào cản bộ nhớ (có hai loại chơi ở đây, nhưng hãy bỏ qua để đơn giản) đảm bảo rằng trường hợp "không" không xảy ra. –

+0

Thẻ được gắn thẻ C#, chứ không phải java – hatchet

+0

Rất tiếc. Tôi đã nhảy giữa các câu hỏi. Quay trở lại với sự hiểu lầm ở đây. –

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