diff --git a/DAIRY.md b/DIARY.md similarity index 96% rename from DAIRY.md rename to DIARY.md index 6529915..8bf0baa 100644 --- a/DAIRY.md +++ b/DIARY.md @@ -1,4 +1,4 @@ -# ccpp/fxalloc/DAIRY.md +# ccpp/fxalloc/DIARY.md # Дисклеймер: * Дневник не является технической документацией. @@ -1077,6 +1077,29 @@ P.S.: Как-то странно, обычно Алиса ругается чт * **CriticalSection** — чуть менее долгий чем предыдущий(имеет ТРД) * **futex** — ещё более продвинутый(Конкорд) * **Абсолютная надёжность** с хитропопны манипуляциями: - * **Атомарные операции(Interlocket/build-ins)** — искомая 3-я космическая + * **Атомарные операции(Interlocked/build-ins)** — искомая 3-я космическая + +## Синхронизация с точки зрения аллокатора + +Единственно верным решением для синхронизации потоков в аллокаторе являются атомарные операции без мьютексов. Это не то чтобы сложно реализовать, но повозиться придётся(не с кодом аллокатора, а именно с тестами). + +## Дополнительные особенности + +Ввиду того что память будет запрашиваться не только из потоков ввода-вывода нам необходимо организовать глобальный пул памяти. Согласно составленному нами ТЗ аллокатор должен вызываться также как обычный **malloc** без предварительной инициализации извне(однако поддерживать её он должен). Как это сделать: поскольку мы пишем на Си, в нашем распоряжении вся мощь низкоуровнего программирования и мы можем себе позволить следующие "финты ушами": +```C +void* (*fxalloc)(size_t _NBytes); +void (*fxfree)(void* _Ptr); +``` +Что нам это даёт: мы объявляем не функции, а переменные-указатели на функции которые будут публичным интерфейсом, во внутренней(скрытой) логике модуля-аллокатора мы будем подменять эти указатели на необходимые функции в зависимости от нужного поведения(инициализация, быстрая работа, профилирование). Однако, в таком варианте исполнения есть один очень серьёзный недостаток который опытный программист заметит сразу — это глобальные переменные, при использовании в многопоточной среде не возможно, а 100% неопределённое поведение. Как решить эту проблему, просто — объявить все функции модуля как внутрипоточные, в таком случае каждый поток получит свои экземпляры указателей на функцции и свой пул памяти в глобальной области без дополнительных расходов: +```C +/* Windows С-11 */ +__declspec(thread) void* (*fxalloc)(size_t _NBytes); +__declspec(thread) void (*fxfree)(void* _Ptr); +/* POSIX С-11 */ +thread_local void* (*fxalloc)(size_t _NBytes); +thread_local void (*fxfree)(void* _Ptr); +``` + +Единственным узким местом остаётся переключение режимов, как это сделать расмотрим далее