Задача на многопоточность. Синхронизация читателей и писателей C#
Есть "сервер" в виде статического класса.
У него есть переменная count (тип int) и два метода, которые позволяют эту переменную читать и писать: GetCount() и AddToCount(int value).
К серверу стучатся множество параллельных клиентов, которые в основном читают, но некоторые добавляют значение к count.
Нужно реализовать GetCount / AddToCount так, чтобы:
- читатели могли читать параллельно, без выстраивания в очередь по локу;
- писатели писали только последовательно и никогда одновременно;
- пока писатели добавляют и пишут, читатели должны ждать окончания записи.
Подскажите как такое делать, или что посмотеть
Ответы (3 шт):
Увеличение на 1:
Interlocked.Increment(ref count);
Увеличение на произвольное значение:
Interlocked.Add(ref count, difference);
Подскажите как такое делать, или что посмотеть
Смотрите код, это очень просто:
public static class MyServer
{
private static int count;
private static ReaderWriterLock locker = new ReaderWriterLock();
public static void AddToCount(int value)
{
locker.AcquireWriterLock(Timeout.InfiniteTimeSpan);
count += value;
locker.ReleaseWriterLock();
}
public static int GetCount()
{
locker.AcquireReaderLock(Timeout.InfiniteTimeSpan);
try
{
return count;
}
finally
{
locker.ReleaseReaderLock();
}
}
}
Сложно придумать пример, который бы наглядно показывал, что все работает, но я попробовал поиздеваться. Пусть четные потоки пишут, а нечетные читают.
static void Main(string[] args)
{
Parallel.For(0, 50, i =>
{
if (i % 2 == 0)
MyServer.AddToCount(2);
else
Console.WriteLine(MyServer.GetCount());
});
Console.WriteLine(MyServer.GetCount());
Console.WriteLine("Done.");
Console.ReadKey();
}
По выводу видно, что оно выполняется несинхронно, а параллельно, выводы в консоль происходят в разное время.
2
8
12
10
4
6
20
22
24
26
28
30
32
34
38
40
36
14
12
44
16
46
18
48
30
50
Done.
Как бы я не пытался перенагрузить класс чтениями и записями из отдельных потоков, последнее число всегда правильно - данном случае 50.
Кстати, в случае с int проще пользоваться атомарными операциями типа Interlocked.Add.
public static class MeServer
{
private static int count;
private static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
public static void AddToCount(int value)
{
locker.EnterWriteLock();
count += value;
locker.ExitWriteLock();
}
public static int GetCount()
{
locker.EnterReadLock();
try
{
return count;
}
finally
{
locker.ExitReadLock();
}
}
}