Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Parallel.For with long running tasks blocks background Timers on NET 6.0 #61804

Copy link
Copy link

Description

@snakefoot
Issue body actions

Description

When starting Parallel.For with more long running tasks than CPU-cores, then suddenly background-timers no longer fires on .NET 6.0. Instead the Parallel.For continues to schedule new threads.

Configuration

When running this snippet on .NET 6.0, then background-Timer stops writing to console.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLogWait;

Console.Title = $"LogDemo - {Environment.ProcessId} (PID)";

var builder = Host.CreateDefaultBuilder(args);

var host = builder
           .ConfigureServices(services =>
           {
               services.AddLogging(builder => builder.AddConsole());
               services.AddHostedService<Worker>();
           })
           .Build();
await host.RunAsync();

namespace NLogWait
{
    public sealed class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger) => _logger = logger;

        private readonly object SyncRoot = new object();
        private Timer Timer;
        private readonly System.Collections.Concurrent.ConcurrentQueue<int> Queue = new System.Collections.Concurrent.ConcurrentQueue<int>();

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Timer = new Timer((s) => TimerExecute());
            _logger.LogInformation("Timer Started");
            Timer.Change(0, Timeout.Infinite);

            Parallel.For(0,
                          200,
                          new ParallelOptions(), // { MaxDegreeOfParallelism = System.Environment.ProcessorCount * 2 },
                          _ =>
                          {
                              _logger.LogInformation("Worker Thead Created");
                              while (!stoppingToken.IsCancellationRequested)
                              {
                                  while (Queue.Count > 1000)
                                  {
                                      lock (SyncRoot)
                                      {
                                          if (Queue.Count < 1000)
                                              break;
                                          Monitor.Wait(SyncRoot);
                                      }
                                  }
                                  Queue.Enqueue(System.Environment.CurrentManagedThreadId);
                              }
                          });

            return Task.CompletedTask;
        }

        private void TimerExecute()
        {
            do
            {
                _logger.LogInformation("Timer Working");

                lock (SyncRoot)
                {
                    for (int i = 0; i < 1000; ++i)
                    {
                        if (!Queue.TryDequeue(out var _))
                            break;
                    }
                    Monitor.PulseAll(SyncRoot);
                }
            } while (Queue.Count > 1000);

            _logger.LogInformation("Timer Scheduled");
            Timer.Change(1, Timeout.Infinite);
        }
    }
}

Regression?

When running on .NET 5.0, then background-timer still get time-slots.

Analysis

The issue disappear when using:

new ParallelOptions() { MaxDegreeOfParallelism = System.Environment.ProcessorCount * 2 },
Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.