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

Когда данные двойной буферизации, это должно быть совместно использованным потоками, я использовал систему, где один поток читает из одного буфера, чтений потока от другого буфера и чтений от первого буфера. Проблема, как я собираюсь реализовать подкачку указателя? Я должен использовать критический раздел? Нет никакой Взаимно блокируемой функции, доступной, который на самом деле подкачает значения. У меня не может быть потока одно чтение из буферного, затем начать читать из буферных двух, посреди чтения, которое было бы appcrash, даже если бы другой поток затем не начал писать в него.

Я использую собственный C++ в Windows в Visual Studio Окончательный RC 2010.

6
задан Dan McGrath 15 February 2010 в 20:27
поделиться

6 ответов

Вы должны создать свою собственную функцию для обмена указателями, которая использует семафор или критическую секцию для управления им. Такая же защита должна быть добавлена ​​для всех пользователей указателей, поскольку любой код, считывающий указатель, находящийся в процессе модификации, является плохим .

Один из способов справиться с этим - заставить всю логику манипулирования указателями работать под защитой блокировки.

1
ответ дан 9 December 2019 в 20:43
поделиться

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

Создайте две критические секции, по одной для каждого из потоков. Во время рендеринга удерживайте критическую секцию render. Другой поток все еще может делать все, что захочет, с другой критической секцией. Используйте TryEnterCriticalSection, и если она удерживается, то верните false, и добавьте объект в список для повторного рендеринга позже. Это позволит нам продолжать рендеринг, даже если данный объект в данный момент обновляется. Во время обновления удерживайте обе секции crit. Во время выполнения игровой логики удерживайте секцию критов игровой логики. Если она уже удерживается, это не проблема, потому что у нас больше потоков, чем реальных процессоров. Так что если этот поток заблокирован, то другой поток просто использует процессорное время, и этим не нужно управлять.

0
ответ дан 9 December 2019 в 20:43
поделиться

Для меня это звучит как проблема типа читатель-писатель-мьютекс.

    [... но я в основном занимаюсь разработкой встраиваемых систем, поэтому это может не иметь смысла для ОС Windows. На самом деле, во встроенной ОС с планировщик на основе приоритетов, вы можете сделать это вообще без какого-либо механизма синхронизации, если вы гарантируете, что обмен является атомарным, и разрешите только потоку с более низким приоритетом менять буферы. ]

Предположим, у вас есть два буфера, B1 и B2, и у вас есть два потока, T1 и T2. Это нормально, если T1 использует B1, а T2 использует B2. Под «использованием» я подразумеваю чтение и / или запись буфера. Затем в какой-то момент буферы необходимо поменять местами, чтобы T1 использовал B2, а T2 использовал B1. Вы должны быть осторожны с тем, что своп выполняется, пока ни один поток не обращается к своему буферу.

Предположим, вы использовали только один простой мьютекс. T1 может получить мьютекс и использовать B1. Если бы T2 захотел использовать B2, ему пришлось бы ждать мьютекса. Когда T1 завершится, T2 разблокируется и выполнит свою работу с B2. Если какой-либо поток (или какой-либо сторонний поток) захочет поменять буферы местами, он также должен будет принять мьютекс. Таким образом, использование всего одного мьютекса сериализует доступ к буферам - не очень хорошо.

Возможно, лучше будет использовать мьютекс для чтения и записи.T1 может получить блокировку чтения на мьютексе и использовать B1. T2 также может получить блокировку чтения на мьютексе и использовать B2. Когда один из этих потоков (или сторонний поток) решает, что пора поменять буферы местами, он должен будет заблокировать запись на мьютексе. Он не сможет получить блокировку записи, пока больше не будет блокировок чтения. В этот момент он может поменять местами указатели буфера, зная, что никто не использует ни один из буферов, потому что, когда на мьютексе есть блокировка записи, все попытки блокировки чтения блокируются.

4
ответ дан 9 December 2019 в 20:43
поделиться

Использование критических секций является общепринятым способом. Просто разделите объект CRITICAL_SECTION между всеми потоками и вызывайте EnterCriticalSection и LeaveCriticalSection на этом объекте вокруг кода манипулирования указателями/чтения/записи буфера. Старайтесь завершать свои критические секции как можно быстрее, оставляя как можно больше кода за пределами критических секций.

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

6
ответ дан 9 December 2019 в 20:43
поделиться

Почему вы не можете использовать InterlockedExchangePointer ?

edit: Хорошо, теперь я понимаю, о чем вы говорите, IEP этого не делает. t фактически меняет местами 2 живых указателя друг с другом, поскольку он принимает только одно значение по ссылке.

1
ответ дан 9 December 2019 в 20:43
поделиться

Вы не упомянули, каковы ограничения вашей платформы Windows, но если вам не нужна совместимость с более старыми версиями, чем Windows Server 2003 или Vista на стороне клиента, вы можете использовать функцию InterlockedExchange64() для обмена 64-битным значением. Упаковывая два 32-битных указателя в 64-битную парную структуру, вы можете эффективно обмениваться двумя указателями.

Существуют обычные варианты Interlocked*; InterlockedExchangeAcquire64(), InterlockedCompareExchange64() и т.д....

Если вам нужно работать, скажем, на XP, я бы выбрал критическую секцию. Когда вероятность возникновения конфликтов мала, они работают довольно хорошо.

0
ответ дан 9 December 2019 в 20:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: