2012-05-17 24 views
5

.Net 3.5'te çok iş parçacığı olan bir windows hizmetim var ve birden çok iş parçacığı oluşturulduğunda hizmetin düzgün bir şekilde durması için bir sorun yaşıyorum.Çok iş parçacıklı pencere hizmetini durdurma

Bu hizmet, tüm işleri yapmak için yalnızca bir iş parçacığı oluşturmak için kullanıldı ve ben bunu çok iş parçacıklı olarak değiştirdim. Mükemmel çalışır, ancak hizmet durdurulduğunda, birden fazla iş parçacığı yürütülürse, tüm iş parçacıkları tamamlanana kadar hizmeti askıya alır.

//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; 
    } 

Ben ayrı sınıfta bir statik değişkeni oluşturdu:

İşte
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; 
     } 

StartThreadPool yöntemidir: Hizmet başlatıldığında

, ana süreç işlemek için bir arka plan iş parçacığı oluşturmak Hizmetin durduğu konuları bildirmek için Bu değişkenin değeri doğru olduğunda, bütün iplikleri (her döngü için) ana döngüyü durdurmak gerekir:

 public static bool StopService; 

Son olarak, OnStop yöntem: ProcessRequestList yöntemde

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

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

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

en Her foreach'in sonu, StopService değişkeninin değerini kontrol ediyorum. Eğer doğruysa, döngüyü kırarım.

İşte sorun: Konular 50 öğeden oluşan parçalar halinde oluşturulmuştur. Veritabanında 50 veya daha az öğe olduğunda, yalnızca bir iş parçacığı oluşturulur ve her şey güzel çalışır. 50'den fazla öğeye sahip olduğumda, birden fazla iş parçacığı oluşturulacak ve hizmeti durdurmaya çalıştığımda, tüm arka plan iş parçacıkları tamamlanana kadar durmuyor.

Günlüklerden, OnStop yönteminin yalnızca tüm iş parçacıklarının tamamlanmasından sonra yürütüldüğünü görebiliyorum.

Bunu düzeltmek için nelerin değiştirilmesi gerektiğine dair bir ipucu var mı?

+0

while döngüsüne Uyku (50) koymayı deneyin. –

+0

Bana öyle geliyor ki, kodun en önemli kısmını eklemediniz. Bu ProcessRequestList yönteminin uygulanmasıdır. –

+0

StopService'in sorgulandığı kodu gösterebilir misiniz? Bu tür bir şey için yapıldığı için, Statlation var sayısının Statik var üzerinden kullanılmasına bakın. – hatchet

cevap

9

Bu blog answer, tüm ThreadPool görevleri tamamlanıncaya kadar OnStop'un çağrılmadığını belirtir; bu, benim için bir haber olur, ancak sorununuzu açıklar.

Çok çok iş parçacıklı Windows Hizmetlerini geliştirdim ancak ThreadPool'u kullanmak yerine kendi arka plan iş parçacıklarımı oluşturmayı tercih ediyorum, çünkü bunlar uzun süren iş parçacıkları. Çalışan sınıflarını başlatıyorum ve iş parçacığı üzerinde DoWork() yöntemini başlatıyorum. Ayrıca, global bir değişkene karşı test yapmaktan ziyade bir durma sinyalini kontrol etmek ve durumu geçmek için başlatma sınıfına geri çağrıları kullanmayı tercih ediyorum.

+0

Sorunu tam olarak çözdünüz. Çok teşekkürler! Bu söylediklerimi anlatıyor, ama beklenen bir davranış olduğunu bilmiyordum. Bunu bildiğim için, şimdi çalışma işlerinde hizmet durumunu kontrol ediyorum ve bir çekicilik gibi çalışıyor. Yine de (henüz) performans açısından ne kadar maliyetli olacağından emin değilim. Teşekkürler! – Roberto

+0

Roberto, çözümünüzü sorunuzda saklamanızı ister misiniz, yoksa boolean StopService değişkeninin anlamı nedir? – PAULDAWG

3

Birden fazla CPU'unuz varsa, StopService erişiminin çevresindeki bellek engellerini kaçırıyorsunuz. Paylaşılan değişkene TÜM erişimler için herhangi bir referans nesneyi daha iyi kilitleyin.

object @lock; 

... 

lock (@lock) 
{ 
    StopService = true; 
} 

Düzenleme: Örneğin başka cevap bildirdiği gibi, bu konunun bir kilitleme sorun değildi, ama ben çoklu işlemli senkronizasyon düzenleri ile kontrol etmek için bir şey olarak burada bu cevabı ayrılıyorum.

Paylaşılan değişkenin geçici hale getirilmesi de birçok durumda işe yarayacaktır, ancak tam çitler yaymadığı için doğru olduğunu kanıtlamak daha karmaşıktır.

+0

Bu, atomiklikle değil, bellek engelleriyle ilgilidir. Atomisite, diğer iş parçacığının hepsini göreceği anlamına gelir - ya da hiç. Bellek bariyeri (burada iki çeşit vardır, ancak bunu basitlik için atlayalım), “hiçbiri” durumunun gerçekleşmemesini sağlar. –

+0

Bu java – hatchet

+0

Oops değil, C# olarak etiketlenmiştir. Sorular arasında atlıyordum. Bu yanlış anlaşılmadan buraya geri döndüm. –

İlgili konular