как синхронизировать двойную буферизацию в многопоточном приложении

У меня есть два потока: один для сбора данных, а другой для отображения. Во избежание ненужной синхронизации. Я использую двойную буферизацию (или перелистывание страниц) следующим образом:

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

Это на самом деле работает хорошо, но иногда (1 на 100 кадров) я вижу разрывы на дисплее, что означает, что все еще существует состояние гонки.

Итак, как мне реализовать минимальную (эффективную) синхронизацию этой двойной буферизации? Мне хватило бы псевдоалгоритма.


person Tae-Sung Shin    schedule 28.12.2011    source источник
comment
Если ваша библиотека графического интерфейса не сделает это за вас, вам также потребуется синхронизировать двойную буферизацию по отношению к сигналу обновления видеокарты. В противном случае можно все еще увидеть некоторые «разрывы», если монитор обновляется в то же время, когда вы перерисовываете свой дисплей.   -  person Jeremy Friesner    schedule 28.12.2011


Ответы (2)


Вы можете сделать это с помощью двух семафоров. Это разновидность проблемы Производитель/Потребитель. Псевдокод в приведенной мной ссылке.

person Miguel    schedule 28.12.2011
comment
Я не использовал семафоры, но использовал более простую структуру очереди без какой-либо блокировки. Это сработало идеально. - person Tae-Sung Shin; 28.12.2011
comment
Хм. Сомневаюсь, что вы решили проблему. Возможно, вы уменьшили вероятность состояния гонки, но без примитивов синхронизации я сомневаюсь, что вы сможете получить 100% надежное решение. - person Miguel; 28.12.2011
comment
ты прав. Мое утверждение было неверным. Наш тест на самом деле проходит, но я понял, что использую синхронизацию, сам того не замечая. - person Tae-Sung Shin; 28.12.2011

С каким языком, платформой и (при необходимости) Graphics API вы работаете?

Мне хватило бы псевдоалгоритма.

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

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

Вот некоторый код, который использует передачу сообщений для синхронизации рендеринга и передачи в графику:

DataAcquisitionThread.Run() {
  ProcessData();
  Wait(message);
  DrawToBackBuffer();
}

DisplayThread.Run() {
  Wait(message);
  SwapBuffer(message.bufferNumber);
  Render(buffer);
  SendMessage(message.defaultMessage());
}
person Keldon Alleyne    schedule 28.12.2011
comment
@Paul: я добавил подход с передачей сообщений. Раньше я использовал его для синхронизации аудиобуферов в системе, в которой не было системы планирования потоков (вместо этого отправка сообщений меняла бы местами работающий поток/процесс). - person Keldon Alleyne; 28.12.2011