Совместное использование потокаобезопасного поля между экземплярами службы Transient в ядре C# / NETC? - PullRequest
0 голосов
/ 04 марта 2020

Мне нужно разделить некоторые блокировки (или «поля объекта») и обычные поля данных между функциями, вызываемыми из службы Transient в. NET Core. Естественно, эти блокировки и поля должны быть объявлены потокобезопасным способом.

Каков наилучший способ приблизиться к нему? Я думаю об отдельном сервисе Singleton. Нужно ли добавлять некоторые ключевые слова в объявленные поля и блокировки, чтобы они были поточно-ориентированными?

Я хорошо знаком с Java многопоточностью, но никогда не делал этого до сих пор в C#.

1 Ответ

0 голосов
/ 04 марта 2020

Это самый простой пример, который я могу придумать. Используется lock. Вы также можете использовать Monitor. В основном я разрешаю временный сервис 3 раза. А затем запустите пару потоков, которые увеличат ценность общего сервиса.

class Program
{
    static async Task Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddSingleton<ValueService>();
        serviceCollection.AddTransient<Service>();
        var provider = serviceCollection.BuildServiceProvider();

        var serviceOne = provider.GetRequiredService<Service>();
        var serviceTwo = provider.GetRequiredService<Service>();
        var serviceThree = provider.GetRequiredService<Service>();

        // Manipulate the same object 1500 times, from different threads.
        var task1 = serviceOne.DoStuff(500);
        var task2 = serviceTwo.DoStuff(500);
        var task3 = serviceThree.DoStuff(500);

        // Wait for all the threads to complete.
        await Task.WhenAll(task1, task2, task3);

        // Verify the result.
        var valueService = provider.GetRequiredService<ValueService>();
        Console.WriteLine(valueService.SomeValue);
        Console.ReadKey();
    }
}

internal class Service
{
    private readonly ValueService _service;

    public Service(ValueService service)
    {
        _service = service;
    }

    public Task DoStuff(int noOfTimes)
    {
        var tasks = new Task[noOfTimes];

        for (int i = 0; i < noOfTimes; i++)
        {
            tasks[i] = Task.Run(() =>
            {
                Thread.Sleep(100);
                _service.Increase();
            });
        }

        return Task.WhenAll(tasks);
    }

}

internal class ValueService
{
    public void Increase()
    {
        // Use lock to make sure that only one thread is changing the field at the time.
        // Remove the lock statement and you will notice some "unwanted" behaviour.
        lock (_lock) 
        {
            SomeValue++;
        }

        // Alternatively you can use Interlocked.Increment(SomeValue)
    }

    private readonly object _lock = new object();
    public int SomeValue { get; private set; }
}
...