Многопоточные Глубокие Копии

#c #multithreading #constructor

Вопрос:

Каков наилучший способ выполнить глубокое копирование в конструкторе объекта, являющегося частью многопоточного кода на C ?

Ответ №1:

Зависит от ваших структур данных.

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

Если вы можете определить группу обеспечения доступности баз данных (то есть частичный порядок), где узлы являются каждой блокировкой в системе, и каждая комбинация блокировок, которую вы, возможно, захотите использовать, соединена ребрами, то вы можете гарантировать, что блокировки никогда не будут приниматься в разных порядках в разных потоках. Следовательно, в частности, вы не получите инверсию блокировки. Типичное правило-брать «самую общую» блокировку последней, так как это, как правило, сводит к минимуму разногласия.

Но если вы глубоко копируете один из целой группы «Ящиков расширения», каждый из которых содержит «Виджеты», которые в основном неразличимы, с возможным перекрытием содержимого ящиков, то у вас естественно возникает проблема с определением порядка блокировки. Кроме того, сначала вам нужно будет заблокировать WidgetBox (даже если это «самый общий» объект), так как без этой блокировки вы не можете сказать, что еще вам нужно заблокировать. Если виджеты сопоставимы, вы можете заблокировать каждый по порядку, скопировать и освободить все. Противный.

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

Другой альтернативой может быть ослабление гарантий, которые вы предоставляете в отношении копии — вместо того, чтобы требовать, чтобы полная копия была сделана из идентифицируемого состояния глубокой структуры, вы можете сначала заблокировать WidgetBox, мелко скопировать его (используя пересчет или что — то еще-блокировка пересчета обычно является «окончательной внутренней блокировкой» и, следовательно, не представляет риска инверсии), освободить блокировку WidgetBox, а затем по очереди скопировать каждый из виджетов. Используйте тот же подход к копированию виджетов, если у них есть внутренняя структура. Результат может содержать виджет в состоянии, которого он не достигал до тех пор, пока он не был удален из виджета в другом потоке, или другие подобные несоответствия, поэтому, если это неприемлемо, вы не можете использовать этот подход. Но если вы когда-либо блокируете только один объект за раз в каждом потоке, то вы не сможете получить инверсию блокировки.

Последний, возможный «ядерный» вариант-сделать все неизменным и всегда копировать при изменении. Если ничто никогда не может быть изменено, то вам не нужны никакие блокировки (хотя вам все равно нужны барьеры памяти при передаче ссылок между потоками).

Если ни одна из этих работ не сработает, то вы вне моего опыта, если только я что-то не забыл. Я бы предположил, что реализация базы данных находится где-то, где происходит много хитростей, связанных с блокировками, и это была бы область, к которой можно было бы обратиться за идеями.

Ответ №2:

вилка()

Я просто шучу. Но это было слишком смешно, чтобы отказаться 🙂

Я думаю, что один из вас рассмотрел большинство ваших вариантов. За исключением, возможно, того, чтобы отступить и посмотреть, сможете ли вы найти способ избежать глубокого копирования в первую очередь…

Ответ №3:

Мой первый порыв (я не эксперт):

Установите блокировку на этом объекте, который код использует для записи в него. При глубоком копировании заблокируйте объект, выполните глубокое копирование, а затем разблокируйте его.

Или я что-то здесь упускаю?

Комментарии:

1. Не так просто, как кажется, учитывая, что здесь речь идет о глубокой копии. В графе объектов потенциально существует множество блокировок для различных фрагментов данных. Очень, очень легко либо пропустить один из них, либо зайти в тупик.