#StackBounty: #c# #windows-services #task-parallel-library Stopping Parallel.ForEach in Windows Service with below normal priority

Bounty: 100

I have a Parallel.ForEach code in my Windows Service. If ParallelOptions.MaxDegreeOfParallelism is set to -1 I’m using the most of my CPU’s. However stopping the service lasts for half a minute. Some internal controller thread that should receive the signal that the service should be stopped is starved out of processor time. I set the process priority to below normal, but that could be irrelevant info here.

What can I do to shorten the time of stopping the service even when all threads are busy?

I was toying with the idea to temporarily lower the priority of the threads from the thread pool, since I don’t have any async code, but Internet says that’s a bad idea, so asking here for a “proper” way.

The threads (both OS and .NET) are in all cases different between OnStart and OnStop. Also, if stopping is very prolonged then the OS thread in which OnStop will sometimes eventually be called is a new thread, not showing earlier in the log.

To build this code create new Windows service project, add ProjectInstaller class from designer, change Account to LocalService, and install once with InstallUtil. Make sure LocalService can write to C:Temp.

public partial class Service1 : ServiceBase
{
    private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    private Task mainTask;
    private StreamWriter writer = File.AppendText(@"C:TempLog.txt");

    public Service1()
    {
        InitializeComponent();

        writer.AutoFlush = true;
    }

    protected override void OnStart(string[] args)
    {
        Log("--------------");
        Log("OnStart");

        mainTask = Task.Run(new Action(Run), cancellationTokenSource.Token);
    }

    protected override void OnStop()
    {
        Log("OnStop");
        cancellationTokenSource.Cancel();

        mainTask.Wait();
        Log("--------------");
    }

    private void Log(string line)
    {
        writer.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}: [{1,2}] {2}",
            DateTime.Now, Thread.CurrentThread.ManagedThreadId, line));
    }

    private void Run()
    {
        using (var sha = SHA256.Create())
        {
            var parallelOptions = new ParallelOptions();
            parallelOptions.MaxDegreeOfParallelism = -1;
            parallelOptions.CancellationToken = cancellationTokenSource.Token;

            Parallel.ForEach(Directory.EnumerateFiles(Environment.SystemDirectory), fileName =>
            {
                if (cancellationTokenSource.IsCancellationRequested)
                    return;

                try
                {
                    var hash = sha.ComputeHash(File.ReadAllBytes(fileName).OrderBy(x => x).ToArray());
                    Log(String.Format("file={0}, sillyhash={1}", fileName, Convert.ToBase64String(hash)));
                }
                catch (Exception ex)
                {
                    Log(String.Format("file={0}, exception={1}", fileName, ex.Message));
                }
            });
        }
    }
}


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.