LINUX.ORG.RU

ctypes, вернуть массив с std::atomic<long long int> и кто освобождает память

 , ,


0

1

Нужна помощь, на стёке не охота вопрошать. Крч имеется std::valarray<std::atomic<long long int>>. Так вот нужно этот массив переметнуть в пейтон. Вопросы:

  1. Можно ли сделать return reinterpret_cast<long long int *>(&a[0]) и не парится (я не думаю что можно просто &a[0] вернуть) или с атомиками не прокатит?

  2. Вот выделяю этому массивообъекту в куче, кто потом будет делать delete? Я так понимаю мне пейтону еще одну функцию надо extern C делать и там ее вызвать?

PS Ни в том ни другом случаю делать копию массива неохота, он т.к. он легко может и под гиг весить.

Надеюсь тут помогут, не зря ж я тут штаны протираю, и я и друганы мои.

ctypes доки: https://docs.python.org/3/library/ctypes.html#pointers



Последнее исправление: BOSS-NIGGER (всего исправлений: 1)

или с атомиками не прокатит?

не прокатит

еще одну функцию надо extern C делать и там ее вызвать?

Хук на удаление питонячьего объекта не повесить?

anonymous
()
Ответ на: комментарий от anonymous

не прокатит

почему?

Хук на удаление питонячьего объекта не повесить?

Всмысле загнать массив в питоновский класс а там в деструкторе прописать?

BOSS-NIGGER
() автор топика

Переметнуть в питон как именно? С передачей владения, без?

  1. По умолчанию предположу что это дичайшее UB. Кроме семантики атомиков, там и выравнивание может быть другое. Но вообще вопрос интересный, по идее должен быть способ после многопоточной работы с массивом атомиков бесплатно сконвертить его в обычную память.

  2. Я не работал с ctypes, но с точки зрения питоновских объектов у тебя есть деструктор (PyTypeObject::tp_dealloc), где ты и освобождаешь всё что нужно. А объект можно сконструировать по-разному:

  • семантика перемещения - забрать в объект оригинальный массив (т.е. с передачей владения, освобождением в dealloc)
  • семантика копирования - т.е. забрать копию (вероятно, в процессе сконверченную в long long*) (аналогично освобождается в dealloc, но оригинальный массив остаётся нетронутым, о его освобождении заботится сишный код который его породил)
  • ссылочная семантика aka. borrow - если есть гарантия что оригинальный массив живёт всё время работы питоновского кода, в объекте достаточно хранить на него указатель и через него предоставлять доступ. Временем жизни управляет сишный код.
  • refcounted, когда неизвестно сишный или питоновский код закончится раньше - что-то среднее между перемещением и ссылкой.
slovazap ★★★★★
()
Ответ на: комментарий от slovazap

по идее должен быть способ после многопоточной работы с массивом атомиков бесплатно сконвертить его в обычную память.

Есть способ «обычную память» «конвертировать» в «атомики»: atomic_ref.

anonymous
()
Ответ на: комментарий от slovazap

Я не работал с ctypes, но с точки зрения питоновских объектов у тебя есть деструктор (PyTypeObject::tp_dealloc), где ты и освобождаешь всё что нужно.

наверное так и сделаю, просто было интересно, может уже есть какой-нибудь встроенный delete [] (пускай который даже я должен вызывать) и не надо писать лишнюю функцию которой опять же этот пойнтер надо будет передавать, ибо не сделаю же я его глобальным.

По умолчанию предположу что это дичайшее UB. Кроме семантики атомиков, там и выравнивание может быть другое. Но вообще вопрос интересный, по идее должен быть способ после многопоточной работы с массивом атомиков бесплатно сконвертить его в обычную память.

Зачем там могло бы понадобиться другое выравнивание? Насколько я понимаю вся семантика атомиков сводится к операциям над ними.

по идее должен быть способ после многопоточной работы с массивом атомиков бесплатно сконвертить его в обычную память.

Я думаю это все же reinterpret_cast, но анон сверху пока тоже высказался отрицательно на этот счет, только пока не сказал почему.

Переметнуть в питон как именно? С передачей владения, без?

С передачей. Конечно тогда встает вопрос что делать с самим валэреем т.к. память выделяю я именно ему, но в принципе это экономия на спичках, пусть течет, жалко мне что ли. Хотя по сути и его надо просто передать как-то. Для этого можно передать пойнтер на массив из пойнтеров пойнтеров, в первой ячейке будет валэррей, во второй сам эррей, во нах, просто идеально.

BOSS-NIGGER
() автор топика
Последнее исправление: BOSS-NIGGER (всего исправлений: 1)
Ответ на: комментарий от anonymous

Похоже, ты серьёзно болен.

Да ладно тебе, самые обыкновенные кресты.

BOSS-NIGGER
() автор топика
Ответ на: комментарий от BOSS-NIGGER

почему?

Нарушение strict aliasing. Нет там правила для преобразования std::atomic<T>* -> T*, поэтому ub

Всмысле загнать массив в питоновский класс а там в деструкторе прописать?

Навроде того

anonymous
()
Ответ на: комментарий от anonymous

Нарушение strict aliasing. Нет там правила для преобразования std::atomic* -> T*, поэтому ub

спасибо за наводку, потом почитаю

Навроде того

да, как-то так и сделаю пожалуй

BOSS-NIGGER
() автор топика
Ответ на: комментарий от slovazap

по идее должен быть способ после многопоточной работы с массивом атомиков бесплатно сконвертить его в обычную память.

Лучше найти способ многопоточной работы без атомиков.

anonymous
()
Ответ на: комментарий от anonymous

Нашел подробности.

https://stackoverflow.com/questions/55547081/assigning-pointers-to-atomic-typ...

/Further, there is the _Atomic qualifier. The presence of the _Atomic qualifier designates an atomic type. The size, representation, and alignment of an atomic type need not be the same as those of the corresponding unqualified type./

/In practice on real implementations, _Atomic T* and T* use the same layout / object representation and alignof(_Atomic T) >= alignof(T)./

/On real implementations, _Atomic may increase the alignment requirement, e.g. a struct {int a,b;} on most ABIs for most 64-bit ISAs would typically only have 4-byte alignment (max of the members), but _Atomic would give it natural alignment = 8 to allow loading/storing it with a single aligned 64-bit load/store. This of course doesn't change the layout or alignment of the members relative to the start of the object, just the alignment of the object as a whole./

То есть как я понял если совпадает репрезентация (как это проверить я не знаю, наверное надо смотреть в доки компилятора) и это труъ:

alignof(std::atomic<T>) == alignof(T)
sizeof(std::atomic<T>) == sizeof(T)

то можно кастовать.

по идее должен быть способ после многопоточной работы с массивом атомиков бесплатно сконвертить его в обычную память.

slovazap

BOSS-NIGGER
() автор топика
Ответ на: комментарий от BOSS-NIGGER

Ты определись, тебя интересует «практический» ответ или формальная корректность. Если первое, то нет смысла читать на SO ответы с тегом language-lawyer, если второе, то ответ на твой первый вопрос строго отрицательный, можешь помечать тему решённой.

anonymous
()
Ответ на: комментарий от anonymous

ответы с тегом language-lawyer

вопросы с тегом language-lawyer

anonymous
()
Ответ на: комментарий от anonymous

Очевидно, меня интересует и та и другая сторона вопроса.

Если первое, то нет смысла читать на SO ответы с тегом language-lawyer

как оказалось смысл есть или те цитаты что я привел сверху этого не доказывают?

PS вопросы на SO я и так никогда не читаю, только ответы

BOSS-NIGGER
() автор топика
Последнее исправление: BOSS-NIGGER (всего исправлений: 1)
Ответ на: комментарий от BOSS-NIGGER

можно кастовать

Можно рисковать, если точнее. Вообще дела такие:

  • нужен корректный c++ код - выкидываешь касты
  • очень хочется заюзать касты - изучаешь доку по компилятору(по всем поддерживаемым версиям), убеждаешься что он корректно реализует такие касты(т. е. это уже не ub, а implementation defined), повторяешь вышеописанное при смене компилятора/версии/окружения
  • ОЧЕНЬ НУЖНЫ КАСТЫ - куришь сгенерённый машкод, убеждаешься что всё норм, при изменении в коде, расположенном поблизости от каста(имеется ввиду execution order) или контекста сборки повторяешь проверку машкода

Ну ещё один вариант очевиден, конечно - просто кастануть, после чего мысленно молиться крестобогам и приносить жертвы компиляторам(не их разработчикам - это не прокатит)

anonymous
()
Ответ на: комментарий от BOSS-NIGGER

как оказалось смысл есть или те цитаты что я привел сверху этого не доказывают?

Если у тебя есть структура, скажем, struct s { int i; };, и у неё такой же размер и выравнивание как у int, то ни массив из int ты не можешь использовать как массив struct s (в смысле, скастить указатель на 0-й элемент массива к указателю на struct s и делать с ним арифметику указателей), ни наоборот.

anonymous
()
Ответ на: комментарий от anonymous

Вообще дела такие: нужен корректный c++ код - выкидываешь касты

Любой C++-код с кастами априори некорректен? Лол.

anonymous
()
Ответ на: комментарий от anonymous

Если у тебя есть структура, скажем, struct s { int i; };, и у неё такой же размер и выравнивание как у int, то ни массив из int ты не можешь использовать как массив struct s (в смысле, скастить указатель на 0-й элемент массива к указателю на struct s и делать с ним арифметику указателей), ни наоборот.

вот я не понимаю почему бы это не должно работать на практике, видимо надо читать про этот алиасинг что бы вдуплить, но оценил бы краткое объяснение и тут.

а то что читал - проблемы алиасинга идут либо от оптимизации либо от выравнивания, в этом примере то что может пойти не так? или всмысле все так, но как анон сверху написал, нужно курить доки и машкод что бы быть уверенным? (что по стандарту так нельзя уже ясно, если что)

BOSS-NIGGER
() автор топика
Ответ на: комментарий от BOSS-NIGGER

вот я не понимаю почему бы это не должно работать на практике

А я говорил что не должно? В рамках UB и не такое работает.

что по стандарту так нельзя уже ясно, если что

Ну ок.

anonymous
()
Ответ на: комментарий от menangen

Тут хвалили python boost c++, ctypes он для взаимодействия с си кодом

ctypes для взаимодействия с си интерфейсом, код можно и на плюсах писать

про python boost когда то че то слышал, но для меня это уже как нибудь в другой раз

BOSS-NIGGER
() автор топика
Ответ на: комментарий от anonymous

может он имел ввиду

Вообще дела такие: нужен корректный c++ код - выкидываешься из окна

BOSS-NIGGER
() автор топика
Ответ на: комментарий от anonymous

Нет конечно, это чушь собачья. Stateless anonymous?

anonymous
()
Ответ на: комментарий от BOSS-NIGGER

Зачем там могло бы понадобиться другое выравнивание? Насколько я понимаю вся семантика атомиков сводится к операциям над ними

Отличий у атомиков от обычных переменных много, причём они разные на разных платформах. Это как минимум другие процессорные инструкции, оптимизационные барьеры для компилятора, особые требования к выравниванию из-за того как работает кэш. Атомик не может пересекать границу кэшлайна даже если требования к выравниванию типа менее строгие. Может где-то он вообще не может попадать в кэшлайн с другими данными.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Да, про кэш я не задумывался.

Это как минимум другие процессорные инструкции, оптимизационные барьеры для компилятора, особые требования к выравниванию из-за того как работает кэш.

Выравнивание мы уже предположили что одинаковое, вместе с размером и репрезентацией. А другие процессорные инструкции - ну так это и есть те самые операции.

Атомик не может пересекать границу кэшлайна даже если требования к выравниванию типа менее строгие.

Это я не очень понял что означает. (а, это походу Cache line contention)

Ну хорошо, кэш. Но как это повлияет на то что я передам кусок памяти питону (или даже начну юзать его дальше в однопоточном коде в той же программе) и что может пойти не так я не вижу если в памяти это массив выглядит как обычный. Может что-то из кэша не успеет перейти назад в память, такое может быть?

PS в конце концов, я как белый человек все сделал через memcpy конечно, компилятор вроде должен с оптимизировать, а тут мне просто интересно понять что к чему.

BOSS-NIGGER
() автор топика
Последнее исправление: BOSS-NIGGER (всего исправлений: 1)
Ответ на: комментарий от BOSS-NIGGER

Всё что надо знать про UB - это UB. Нет никакого «что к чему». Это UB, точка. Что вы можете сделать - заглянуть в стандарт и посмотреть всё-таки что с массивом атомиков делать допустимо. Мне за вас это делать, честно, лень.

slovazap ★★★★★
()

std::valarray<std::atomic>

Это бред собачий. Поддержу анонимного психиатра выше на тему болезни.

Впрочем, вот до чего в итоге доводят кресты, да, и соответственно, почему практически весь реальный код на крестах - глючное, текущее памятью и тормозное говно.

lovesan ★★
()
Ответ на: комментарий от BOSS-NIGGER

PS в конце концов, я как белый человек все сделал через memcpy конечно, компилятор вроде должен с оптимизировать, а тут мне просто интересно понять что к чему.

А ты уверен, что memcpy на атомиках будет корректно работать?

im-0
()
Ответ на: комментарий от BOSS-NIGGER

Или есть причины по которым он может сломаться?

Я не настоящий сварщик, но мне кажется, что сломаться может. Например, если другие потоки используют эти атомики именно как атомики, а memcpy реализована простейшим способом - копированием отдельными байтами.

im-0
()
Ответ на: комментарий от im-0

К тому моменту когда я копирую все операции уже завершены. Мне кажется за этим следит проц на каком-то уровне, но я хз как устроены атомики. Кастану военов из соседней темы, они скорее всего знают @example_cat @byko3y

ctypes, вернуть массив с std::atomic<long long int> и кто освобождает память (комментарий)

BOSS-NIGGER
() автор топика

Зачем вы меня кастуете в эту порнографию? Я сразу по заголовку вижу, что автор хочет жесткое садомазо с заковыванием и хлестанием до крови. Детали реализации меня уже не особо волнуют.

byko3y ★★★★
()
Ответ на: комментарий от lovesan

А что, если нужно распаралеллить алгоритм который складывает результат в массив данных (просто плюсует к уже там находящемуся), есть другие годные варианты? Да, можно создать и свой массив под каждый тред (и в конце их с собой сложить), но это минус память и минус эффективность кэша.

BOSS-NIGGER
() автор топика
Ответ на: комментарий от byko3y

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

memcpy на атомиках будет корректно работать?

(Атомики в момент memcpy уже не используются, конечно.)

BOSS-NIGGER
() автор топика
Ответ на: комментарий от BOSS-NIGGER

memcpy на атомиках будет корректно работать?

Они скопируются точно так же, как скопируется любая другая память, поскольку это и есть обычная память:

template<typename _ITp>
struct __atomic_base
    {
    private:
      typedef _ITp         __int_type;
      alignas(_S_alignment) __int_type _M_i;

byko3y ★★★★
()

массив атомных long long int = массиву long long int. можно отдать тупо адрес массива.

example_cat
()
Ответ на: комментарий от ei-grad

Сомневаюсь что у него там специальный код для атомиков, но если будет проект где нужно будет много функций передавать питону, я посмотрю, спасибо.

BOSS-NIGGER
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.