Код: Выделить всё
internal class ClientManager : IClientManager
{
private readonly HashSet _clients = new HashSet();
private readonly ReaderWriterLock _lock = new ReaderWriterLock();
public IEnumerable Clients
{
get
{
try
{
_lock.AcquireReaderLock(100.Milliseconds());
var result = _clients.ToList();
return result;
}
finally
{
_lock.ReleaseReaderLock();
}
}
}
public void AddClient(Guid clientId, string login, string appName)
{
try
{
_lock.AcquireWriterLock(100.Milliseconds());
_clients.Add(clientId);
}
finally
{
_lock.ReleaseWriterLock();
}
}
public void RemoveClient(Guid clientId)
{
try
{
_lock.AcquireWriterLock(100.Milliseconds());
_clients.Remove(clientId);
}
finally
{
_lock.ReleaseWriterLock();
}
}
}
Код: Выделить всё
[Fact]
public void ClientManager_Should_Handle_Concurent_Operations()
{
var clientManager = new ClientManager();
var isDoneAdding = false;
var addTask = new Task(() =>
{
for (var i = 0; i < 10000; i++)
{
//Adding client should enter write lock
clientManager.AddClient(Guid.NewGuid(), $"login_{i}", $"appName_{i}");
}
isDoneAdding = true;
});
var accessTask = new Task(() =>
{
for (var i = 0; i < 10000; i++)
{
//Getting clients should enter read lock
var clients = clientManager.Clients;
}
});
var removeTask = new Task(() =>
{
for (var i = 0; i < 10000; i++)
{
var existingGuid = clientManager.Clients.FirstOrDefault();
if (existingGuid != default)
{
//Removing client should enter write lock
clientManager.RemoveClient(existingGuid);
}
}
//refactor that
while (clientManager.Clients.Count() > 0 && isDoneAdding)
{
var existingGuid = clientManager.Clients.FirstOrDefault();
if (existingGuid != default)
{
clientManager.RemoveClient(existingGuid);
}
}
});
accessTask.Start();
addTask.Start();
removeTask.Start();
Task.WaitAll(accessTask, addTask, removeTask);
Assert.True(clientManager.Clients.Count() == 0);
}
Неудачный тест
Я изменил хэш-набор и систему блокировки для параллельного словаря следующим образом:
р>
Код: Выделить всё
internal class ClientManager : IClientManager
{
//We don't need the value here so just put a byte to reduce memory footprint
private readonly ConcurrentDictionary _clients = new ConcurrentDictionary();
private readonly ReaderWriterLock _lock = new ReaderWriterLock();
public IEnumerable Clients
{
get
{
return _clients.Keys;
}
}
public void AddClient(Guid clientId, string login, string appName)
{
_clients.TryAdd(clientId, default);
}
public void RemoveClient(Guid clientId)
{
_clients.Remove(clientId, out _);
}
}
Я не понимаю, чего мне не хватает в системе блокировки хешсета это работает, может кто-нибудь помочь мне понять, что происходит?
Спасибо за чтение!
Подробнее здесь: https://stackoverflow.com/questions/786 ... erent-resu