Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

AddExpirationToken extension is not thread safe #247

Closed
JunTaoLuo opened this issue Oct 31, 2016 · 2 comments
Closed

AddExpirationToken extension is not thread safe #247

JunTaoLuo opened this issue Oct 31, 2016 · 2 comments
Assignees

Comments

@JunTaoLuo
Copy link
Contributor

I've noticed that CacheEntryScopeExpirationTests.LinkContexts_AreThreadSafe test can occasionally fail when run repeatedly at https://github.com/aspnet/Caching/blob/dev/test/Microsoft.Extensions.Caching.Memory.Tests/CacheEntryScopeExpirationTests.cs#L475.

I will usually see one or two failures when repeating this test 50 times. I have reproduced this on Win10 x64 and Win10 x86.

cc @Tratcher

@muratg muratg added this to the 1.2.0 milestone Nov 21, 2016
@JunTaoLuo JunTaoLuo changed the title Flaky failures of Microsoft.Extensions.Caching.Memory.CacheEntryScopeExpirationTests.LinkContexts_AreThreadSafe AddExpirationToken extension is not thread safe Dec 28, 2016
@JunTaoLuo
Copy link
Contributor Author

JunTaoLuo commented Dec 28, 2016

Looks like the AddExpirationToken (

public static ICacheEntry AddExpirationToken(
this ICacheEntry entry,
IChangeToken expirationToken)
{
if (expirationToken == null)
{
throw new ArgumentNullException(nameof(expirationToken));
}
entry.ExpirationTokens.Add(expirationToken);
return entry;
}
) is not thread safe.

The issue arises when AddExpirationToken is called from different threads concurrently. Since they operate on the underlying ExpirationTokens, an IList, is not thread safe, some tokens may not be added.

A few possible fixes (need to make sure this doesn't introduce other races/deadlocks):

  1. Use ICollection.SyncRoot of the ExpirationTokens collection for synchronization.
  2. There's already a lock object for each entry we can use for synchronization though it's not exposed. We can move this extension to the interface instead.
  3. MakeExpirationTokens a thread safe collection

Should review handling of expiration tokens for other potential races.

@Tratcher
Copy link
Member

Tratcher commented Jan 6, 2017

If there's going to be a lock it should be here:

parent.AddExpirationToken(expirationToken);

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants