Спільна пам'ять у C
У C# спільна пам'ять означає пам'ять, яка доступна для кількох компонентів або потоків у межах одного додатка. Цей термін часто використовується в контексті статичних полів, доменів додатків та мультитредінгу. Спільна пам'ять дозволяє ефективно обмінюватися даними, але вимагає ретельного керування, щоб уникнути проблем, таких як умови гонки.
1. Спільна пам'ять у статичних полях
У C# статичні поля зберігаються в спільній пам'яті, що означає:
- Статичне поле належить самій класу, а не конкретному екземпляру.
- Усі екземпляри класу ділять ту саму копію статичного поля.
- Статичні поля зберігаються в кучі, але вони виділяються лише один раз для додатка (або AppDomain).
Приклад спільної пам'яті в статичних полях
class MyClass
{
public static int SharedCount = 0; // Спільна пам'ять для всіх екземплярів
}
class Program
{
static void Main()
{
MyClass.SharedCount++;
Console.WriteLine(MyClass.SharedCount); // Виведеться: 1
MyClass.SharedCount++;
Console.WriteLine(MyClass.SharedCount); // Виведеться: 2
}
}
- Поле
SharedCount
інкрементується всіма екземплярамиMyClass
, що відображає спільну природу статичних полів.
2. Спільна пам'ять у мультитредінгу
Коли кілька потоків ділять одну й ту ж пам'ять (наприклад, доступ до тих самих статичних полів або властивостей класу), це може призвести до проблем з паралельним виконанням, таких як умови гонки або пошкодження даних.
Приклад: Спільна пам'ять з потоками
using System;
using System.Threading;
class Counter
{
public static int Count = 0; // Спільна пам'ять
}
class Program
{
static void Main()
{
Thread t1 = new Thread(() => { for (int i = 0; i < 1000; i++) Counter.Count++; });
Thread t2 = new Thread(() => { for (int i = 0; i < 1000; i++) Counter.Count++; });
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine(Counter.Count); // Може бути не 2000 через умови гонки
}
}
У цьому прикладі:
- Обидва потоки змінюють статичне поле
Counter.Count
, яке знаходиться в спільній пам'яті. - Без належної синхронізації результат може бути неконсистентним.
Рішення: Синхронізація
Ви можете використовувати блокування для захисту спільної пам'яті від одночасного доступу:
class Counter
{
private static object lockObj = new object();
public static int Count = 0;
public static void Increment()
{
lock (lockObj)
{
Count++;
}
}
}
3. Домен додатків і спільна пам'ять
- У попередніх версіях .NET (до .NET Core) домен додатка (AppDomain) забезпечував ізоляцію між різними додатками, що працюють в одному процесі.
- Статичні поля були спільними в межах одного AppDomain, але ізольовані між різними AppDomains.
У .NET Core та .NET 5+ AppDomains були замінені на більш легкі механізми, такі як AssemblyLoadContext.
4. Спільна пам'ять у паралельному програмуванні
У паралельному програмуванні (наприклад, використовуючи Tasks, PLINQ або ThreadPool) спільна пам'ять повинна ретельно керуватися, щоб уникнути пошкодження даних. Інструменти, такі як конкурентні колекції або взаємно блокуючі операції, можуть допомогти.
Приклад: Використання Interlocked для потокобезпечної спільної пам'яті
using System;
using System.Threading;
class Counter
{
public static int Count = 0;
}
class Program
{
static void Main()
{
Thread t1 = new Thread(() =>
{
for (int i = 0; i < 1000; i++)
Interlocked.Increment(ref Counter.Count); // Потокобезпечний інкремент
});
Thread t2 = new Thread(() =>
{
for (int i = 0; i < 1000; i++)
Interlocked.Increment(ref Counter.Count); // Потокобезпечний інкремент
});
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine(Counter.Count); // Виведеться: 2000
}
}
## Спільна пам'ять у міжпроцесорній комунікації (IPC)
Якщо кілька процесів повинні ділити пам'ять:
- Можна використовувати **файли з відображенням пам'яті**.
- Це дозволяє процесам читати та записувати в одну й ту саму область пам'яті.
### Приклад: Спільна пам'ять з файлами з відображенням пам'яті
using System;
using System.IO.MemoryMappedFiles;
class Program
{
static void Main()
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen("SharedMemory", 1024))
{
using (var accessor = mmf.CreateViewAccessor())
{
accessor.Write(0, 42); // Запис у спільну пам'ять
int value = accessor.ReadInt32(0); // Читання зі спільної пам'яті
Console.WriteLine(value); // Виведе: 42
}
}
}
}
```
Ключові моменти
- Статичні поля:
- Спільні для всіх екземплярів класу.
- Зберігаються в одному місці в купі.
2. Безпека потоків:
- Спільна пам'ять між потоками потребує синхронізації (наприклад, блокування або взаємно блокуючі операції).
3. Міжпроцесорна комунікація (IPC):
- Файли з відображенням пам'яті дозволяють спільну пам'ять між процесами.
Перекладено з: Shared Memory in C#