Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast Concurrent Data-Structures Through Explicit Timestamping(deque) #55

Open
wants to merge 16 commits into
base: integration
Choose a base branch
from

Conversation

kiborrdis
Copy link

Попытка реализации структуры данных описанных в этой статье, с использованием hazard pointers.
http://arise.or.at/pubpdf/Fast_Concurrent_Data-Structures_Through_Explicit_Timestamping.pdf

Интерфейс делался на примере fcdeque из библиотеки.
Добавлены hdr тесты для структуры данных(фактически взяты из тестов для fcdeque).
В папке unit нет тестов на деки, как писать те тесты не разобрался. В принципе можно сделать на основе дека стек и очередь и подключить к тестам, но не уверен насколько в этом есть смысл в плане проверки работоспособности дека.

@khizmax
Copy link
Owner

khizmax commented Feb 23, 2016

Мне требуется время, чтобы освежить в памяти исходный алгоритм.
Пока могу высказать только несколько технических замечаний:

  1. Запихнуть в реализацию структуры данных asm volatile - смелый ход, который приводит к тому, что реализация становится зависимой и от железа (x86) и от компилятора (gcc/clang). Такие вещи выносят куда-нибудь в cds/compiler. Сама реализация структуры данных должна быть независимой от платформы и компилятора.
  2. Выкидывание исключений здесь излишне. Исключения - довольно тяжелая фича, использовать их надо к месту. А если использовать, то они должны быть осмысленными, - throw -1 под определение осмысленности не подходит. И указание throw в объявлениях функций,
    типа guard* tryRemoveRight() throw(int), объявлено deprecated в C++11.
  3. Нестандартное использование cds::gc::HP::guard. Я не предполагал, что их нужно создавать в куче (через new). Динамическое распределение памяти тоже является тяжелой и в общем случае блокирующей операцией. Guards должны располагаться на стеке, пока вы мне не докажете обратное ;-)
  4. GC должен быть аргументом template класса. В libcds есть две реализации HP - gc::HP и gc::DHP, с точки зрения использования в контейнерах они неразличимы. Но DHP не зависит от числа потоков. Как следствие, maxThread становится аргументом конструктора класса.
  5. Объявления вида bnode*** (третий уровень косвенности!) всегда говорят о том, что в коде не все в порядке.

@kiborrdis
Copy link
Author

Здравствуйте. Спасибо за замечания!

  1. Понял, вынесу.
  2. Согласен, исправлю
  3. Просто после чтения документации, и попытках чтения кода, видимо я так и не понял до конца как их правильно использовать. Насколько я понимаю сейчас, после вашего комментария, объявление GuardArray необходимого размера и последующее использование его в коде будет тем способом которым предполагается использование guard-ов? Или это не так? Я про стек тоже видимо до конца не понял
  4. Добавлю параметром
  5. В оригинальной статье функции empty уделяется строчек 8 и дается ссылка на статью подход из которой использован. Для каждого потока нужны массивы(длинной равной количеству потоков) в которых хранятся локальные для потока данные(соответственно maxThread массивов длинной maxThread). Я сделал двумерный массив указателей на bnode, и каждый поток получает доступ к своему массиву через свой индекс.
    Может я не понял подход который используется для функции empty( статьи на которую они ссылаются в открытом доступе нет, а доступ мне не дали). Но из вариантов как сделать по другому в голову приходит только, разве что, использование thread specific ptr в котором хранится ссылка на массив конкретного thread-а.

@khizmax
Copy link
Owner

khizmax commented Feb 24, 2016

Насколько я понимаю сейчас, после вашего комментария, объявление GuardArray необходимого размера и последующее использование его в коде будет тем способом которым предполагается использование guard-ов? Или это не так? Я про стек тоже видимо до конца не понял
Размещение на стеке - это объявление локальной переменной. Обычное использование GuardArray - объявление в member function локальной переменной типа GuardArray<Const>. Далее, если нужно, передается ссылка на неё во все вложенные вызовы.

В оригинальной статье функции empty() уделяется строчек 8 и дается ссылка на статью подход из которой использован
Чтобы ответить на этот вопрос - как сделать empty() - мне потребуется некоторое время на осмысление оригинального алгоритма. Пока что на правильный empty() можно забить и постулировать, что у нас должен быть непустой счетчик элементов (типа cds::atomicity::item_counter). Тогда empty() - это просто сравнение счетчика с нулем.

@khizmax
Copy link
Owner

khizmax commented Feb 24, 2016

Насчет multi-threaded (stress) тестов. Да, тестов на deque (пока) нет. Я их тестирую как стек и как очередь, причем с обоих концов - лево/правосторонний стек и лево/правосторонняя очередь.
Как подключать стек - см. мой коммент здесь - #54.

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

Successfully merging this pull request may close these issues.

2 participants