многопоточность — удаление рабочего элемента многопоточного загрузчика текстур C ++ из основного потока

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

Запрос загрузчика текстуры — это простая структура с необработанным указателем на объект, который получит текстуру:

struct TextureLoaderRequest
{
std::string mFilename;
ContentViewer *mContentViewer;
};

Фактический объект текстуры, содержащийся в ContentViewer, защищен мьютексом и некоторыми атомарными логическими значениями (также содержащимися в ContentViewer):

std::atomic<bool>               mIsLoaded;
std::atomic<bool>               mIsVisible;
std::mutex                      mImageMutex;

Тогда процедуры доступа к текстуре выглядят следующим образом:

void ContentViewer::setTexture(ci::gl::TextureRef texture)
{
std::lock_guard<std::mutex> guard(mImageMutex);
mImage = texture;
}

ci::gl::TextureRef ContentViewer::getTexture()
{
std::lock_guard<std::mutex> guard(mImageMutex);
if (mIsVisible)
{
if (mImage != nullptr)
{
mIsLoaded = true;
return mImage;
}
mIsLoaded = false;
}
return nullptr;
}

Загрузчик текстур может получать много запросов на загрузку текстур из основного потока за один раз, а затем обрабатывает загрузку очереди и присваивает текстуры зрителю контента, указанному в сообщении запроса на загрузку текстур.

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

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

Спасибо
— Laythe

1

Решение

Итак, есть два варианта imho:

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

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

0

Другие решения

Я обнаружил, что мне нужно создать список отмены из защищенного вектора std :: mutex. Когда основной поток хочет выйти, он просто добавляет запись в вектор и продолжает работу. Поток загрузчика текстур несет дополнительную нагрузку по проверке списка для каждого полученного запроса текстуры, но операция не находится на критическом пути.

Я все еще был бы заинтересован в альтернативах / предложениях.

Небольшая схема темы ниже:

void textureLoaderThreadFn()
{
log("texture loader thread started");

while (!mShouldQuit)
{
// Wait for texture loader request
TextureLoaderRequest *textureLoaderRequest = nullptr;
mTextureRequests->popBack(&textureLoaderRequest);

// it is possible popBack didnt modify textureLoaderRequest (eg. when cancelled on exit)
if (textureLoaderRequest != nullptr)
{
std::lock_guard<std::mutex> lk(mCancellationListMutex);

if (std::find(mCancellationList.begin(), mCancellationList.end(), textureLoaderRequest->mFilename) != mCancellationList.end())
{
// Cancelled

// we must reset the isLoading that was set by the main thread,
// so that the request to load the texture can get put back if need be
textureLoaderRequest->mContentViewer->mIsLoading = false;

// remove from cancellation list
mCancellationList.erase(std::remove(mCancellationList.begin(), mCancellationList.end(), textureLoaderRequest->mFilename), mCancellationList.end());
}
else
{
// Not cancelled
<SERVICE TEXTURE REQUEST>
}

// dont need this anymore
delete textureLoaderRequest;
}
}
log("texture loader thread stopped");

// Empty the queue
int count = 0;
TextureLoaderRequest *textureLoaderRequest = nullptr;
while (mTextureRequests->tryPopBack(&textureLoaderRequest))
{
if (textureLoaderRequest != nullptr)
delete textureLoaderRequest;
count++;
}
log("texture loader thread purged " + std::to_string(count) + " outstanding texture load requests");
}
0

Я бы посоветовал вам добавить флаг статуса в просмотрщик контента, чтобы различать 3 статуса; окрашивается и окрашивается, а не окрашивается.
Основной поток должен удалять средство просмотра контента только тогда, когда его состояние запланировано для окрашивания или не запланировано для окрашивания.

Рабочий поток текстур меняет статус на цветной, и как только он окрашен, он помещается в цветной.

Изменение статусов и проверка статуса, если он может быть удален, всегда должны определяться одним и тем же мьютексом; Вы можете поместить флаг как частный в просмотрщике контента и использовать два открытых метода: 1) void change_status (status) и 2) bool can_delete ().

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

В рабочем потоке текстуры перед выходом вы можете удалить последнее цветное содержимое в том случае, если оно не было удалено основным потоком (как если бы оно находилось в цветном состоянии).

0
По вопросам рекламы [email protected]