cnblogs / EnyimMemcachedCore

.NET Memcached client. Available on https://www.nuget.org/packages/EnyimMemcachedCore
Apache License 2.0
162 stars 45 forks source link

Increment multithreading issue #207

Open MarkoPielic opened 10 months ago

MarkoPielic commented 10 months ago

Increment operation should be thread safe and atomic, but it is not - at least not when the key you are trying to increment does not exist.

If you try to do this:

 var result = memcachedClient.Increment(key, 1, 1, TimeSpan.FromDays(2));
 Console.WriteLine("Increment value: " + result);

From the single thread it will work as expected. But if you try to do it from multiple threads it will sometimes work as expected and sometimes not (roughly about 50-50).

Full program to reproduce the issue (running on .NET 6) is below.

using Enyim.Caching;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfiguration configuration = builder.Build();

var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(configuration);
serviceCollection.AddLogging();
serviceCollection.AddEnyimMemcached();

var serviceProvider = serviceCollection.BuildServiceProvider();
var memcachedClient = serviceProvider.GetService<IMemcachedClient>();

string key = Guid.NewGuid().ToString();
List<Task> tasks = Enumerable.Range(1, 10)
    .Select(item => Task.Run(() =>
    {
        var result = memcachedClient.Increment(key, 1, 1, TimeSpan.FromDays(2));
        Console.WriteLine("Increment value: " + result);
    }))
    .ToList();

await Task.WhenAll(tasks);

var result = await memcachedClient.GetAsync<string>(key);
Console.WriteLine("Final result: " + result.Value);

CURRENT BEHAVIOR

EXPECTED BEHAVIOR