Контекст: В одном из моих приложений на C ++ 11 сериализация объектов и публикация сообщений занимают много времени.Поэтому я хочу сделать это в отдельном потоке, используя библиотеку Intel TBB (более конкретно, используя tbb :: task_group )
Issue : объект для сериализации являетсяструктура, в которой некоторые свойства std::vector<std::unique_ptr<SomeObject>>
, что делает невозможным передачу копии в лямбду, выполненную в задаче
Примерно это выглядит как
struct MockedDC {
MockedDC(int x, std::vector<std::unique_ptr<SomeObject>> v) : x(x),
v(std::move(v)) {};
int x;
std::vector<std::unique_ptr<SomeObject>> v;
};
"Решение", которое я нашел, должен восстановить в куче конструктор перемещения моего экземпляра и обернуть его в shared_ptr<MockedDC>
, который можно копировать.В конце концов, функция, которая вызывает tbb::task_group::run
, выглядит как
// function called like this `executeInThread(taskGroup, std::move(mockedDC))`
void executeInThread(tbb::task_group& taskGroup, MockedDC mockedDC) {
const std::shared_ptr<MockedDC> sharedMockedDC(new MockedDC(std::move(mockedDC)));
auto f = [sharedMockedDC] {
const auto serialized(serializer(*sharedMockedDC)); // pass by reference
publish(serialized);
};
taskGroup.run(f);
};
, она компилируется и работает нормально, но я не могу подвергнуть ее давлению, так как это будет в реальной жизни, поэтому мой вопрос это безопасно / разумно делать это?
Я нашел в другом stackoverflow вопрос альтернативы , но реализация выглядит сложной для поддержки, учитывая мойЗнание C ++ :), поэтому я хочу придерживаться подхода shared_ptr
, как это было предложено где-то еще
Что я пробовал до сих пор: Я написал фиктивный код дляпроверить вещь, но я думаю, что этого недостаточно для проверки этого подхода.Я также хотел скомпилировать с некоторыми флагами очистки, но tbb не удалось связать с кучей ошибок, таких как undefined reference to __ubsan_handle_pointer_overflow
Вот пример фиктивного примера, если это помогает ответить (он компилируется и запускается без проблем (кроме некоторыхпереполнение int, но это не проблема, я думаю))
#include <cstdio>
#include <iostream>
#include <memory>
#include <vector>
#include <numeric>
#include "tbb/task_scheduler_init.h"
#include "tbb/task_group.h"
struct MockedDC {
MockedDC(int seed, size_t baseLen) : seed(seed), baseLen(baseLen) {
this->a_MDC.reserve(baseLen);
for (size_t i = 0; i < baseLen; ++i)
this->a_MDC.emplace_back(new int((seed + i) / (seed + 1)));
};
int seed;
size_t baseLen;
std::vector<std::unique_ptr<int>> a_MDC;
};
void executeInThread(tbb::task_group& taskGroup, MockedDC mockedDC) {
const std::shared_ptr<MockedDC> sharedMockedDC(new MockedDC(std::move(mockedDC)));
auto f = [sharedMockedDC] {
std::cout <<
std::accumulate(sharedMockedDC->a_MDC.begin(), sharedMockedDC->a_MDC.end(), 0, [](int acc, const std::unique_ptr<int>& rhs) {
return acc + *rhs;
})
<< std::endl << std::flush;
};
taskGroup.run(f);
};
void triggerTest(tbb::task_group& taskGroup) {
for (size_t i = 0; i < 1000000; ++i) {
MockedDC mdc(i, 10000000);
executeInThread(taskGroup, std::move(mdc));
}
return ;
};
int main() {
tbb::task_scheduler_init tbbInit(tbb::task_scheduler_init::automatic);
//tbb::task_scheduler_init tbbInit(8);
tbb::task_group taskGroup;
triggerTest(taskGroup);
taskGroup.wait();
return (0);
};
PS: использование C ++ 14 нового захвата при перемещении не работает из-за библиотеки TBB: /