Использование переменных-членов unique_ptr или нет?

Какой лучший шаблон дизайна для создания очереди блокирующих буферов, который эффективно использует ресурсы в C ++ 11/14 без слишком большого количества ассигнований / перемещений? С помощью Queue<std::unique_ptr<Workitem>>

ИЛИ ЖЕ

Queue<Workitem> и с этим скрывая управление ресурсами в реализации (немного похоже на контейнеры stl). Обратите внимание, вторая идея (очередь) закомментирована. Каковы последствия закомментированной версии также в отношении кучи / стека? А как насчет использования std::unique_ptr<Queue<Workitem>> q?

Я не очень хорош с C ++, но независимо от версии, я не могу действительно утечка памяти, верно? (повторение: не новое / удалить -> нет утечек памяти)

Код здесь:

#include <condition_variable>
#include <mutex>
#include <queue>

template <class T> class Queue {
public:
Queue(size_t size);

// push item to _queue if _queue.size() < _size
// else block
void push(T item);
// void push(std::unique_ptr<T> item);

// pop item if !_queue.empty()
// else block or return false after timeout
bool pop(T &item);
// bool pop(std::unique_ptr<T> &item);

private:
std::mutex _mutex;
std::size_t _size;

std::queue<T> _queue;
// std::queue<std::unique_ptr<T>> _queue;

std::condition_variable _condition_full;
std::condition_variable _condition_empty;
};

struct Workitem {
size_t idx;
void *workdetails;
};

void do_work(Queue<std::unique_ptr<Workitem>> &work_q,
Queue<std::unique_ptr<Workitem>> &write_q,
struct options_s &opts) {
std::unique_ptr<Workitem> work;
while (work_q.pop(work)) {
// calculation w/ work
std::unique_ptr<Workitem> res = consume(work, opts);
write_q.push(std::move(work));
}
}
void do_write(Queue<std::unique_ptr<Workitem>> &write_q,
struct options_s &opts) {
std::unique_ptr<Workitem> work;
while (write_q.pop(work)) {
prepare_for_writing(work, opts); // clean item
write(work);
}
}

auto w1 = std::thread(do_work, std::ref(work_q), std::ref(write_q),
std::ref(options));
auto w2 = std::thread(do_work, std::ref(work_q), std::ref(write_q),
std::ref(options));
auto writer = std::thread(do_write, std::ref(write_q), std::ref(options));

int main() {
Queue<std::unique_ptr<Workitem>> work_q{4};
Queue<std::unique_ptr<Workitem>> write_q{4};
// Queue<Workitem> q{4};
// ??? std::unique_ptr<Queue<Workitem>> q{4} ???

for (size_t i, ...) { // do many iterations
std::unique_ptr<Workitem> w{};
// Workitem w{};

populate(w, i); // populate work item

work_q.push(std::move(w));
}

w1.join();
w2.join();
writer.join();
}

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

ура

0

Решение

Какой лучший шаблон дизайна для создания очереди блокирующих буферов, который эффективно использует ресурсы в C ++ 11/14 без слишком большого количества ассигнований / перемещений? С помощью Queue<std::unique_ptr<Workitem>> ИЛИ ЖЕ Queue<Workitem>

Учитывая эти критерии, Queue<Workitem> лучше, потому что он избегает одного слоя динамического распределения.

Каковы последствия закомментированной версии также в отношении кучи / стека?

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

Я не могу действительно утечка памяти, верно? (повторение: не новое / удалить -> нет утечек памяти)

Твои рассуждения верны. Пример кода, который вы показываете, не имеет утечек памяти.

Там, однако, есть пустая переменная-член указателя Workitem::workdetails это может привести к утечкам памяти, если он используется не по назначению (если ему когда-либо принадлежит память, на которую он указывает).

2

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

Других решений пока нет …

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