У меня есть поток загрузки текстур, который получает запросы на загрузку текстур из основного потока через параллельную очередь.
Запрос загрузчика текстуры — это простая структура с необработанным указателем на объект, который получит текстуру:
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
Итак, есть два варианта imho:
У меня нет достаточного понимания вашего приложения: как реализована очередь и почему и когда запланированы запросы, поэтому я не могу дать отзыв об этом.
Я обнаружил, что мне нужно создать список отмены из защищенного вектора 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");
}
Я бы посоветовал вам добавить флаг статуса в просмотрщик контента, чтобы различать 3 статуса; окрашивается и окрашивается, а не окрашивается.
Основной поток должен удалять средство просмотра контента только тогда, когда его состояние запланировано для окрашивания или не запланировано для окрашивания.
Рабочий поток текстур меняет статус на цветной, и как только он окрашен, он помещается в цветной.
Изменение статусов и проверка статуса, если он может быть удален, всегда должны определяться одним и тем же мьютексом; Вы можете поместить флаг как частный в просмотрщике контента и использовать два открытых метода: 1) void change_status (status) и 2) bool can_delete ().
Обе функции должны начинаться с получения одного и того же мьютекса. 1) для использования в различных переходах в основном потоке и в рабочем потоке текстур, и 2) используется основным потоком перед удалением средства просмотра содержимого, чтобы возвращать значение true, только если состояние не окрашено.
В рабочем потоке текстуры перед выходом вы можете удалить последнее цветное содержимое в том случае, если оно не было удалено основным потоком (как если бы оно находилось в цветном состоянии).