
Azoyan
03.08.2018
16:30:28
Мопед не мой

Ilia
03.08.2018
16:31:11


Erik
03.08.2018
17:48:46
Всем добрый вечер. Нужна ваша помощь. Битый час сижу голову ломаю. Вот есть пример пула задачь: https://github.com/mtrebi/thread-pool
В все вроде достаточно знакомо. Ни разу с подобными пулами небыло проблем, пока не захотел вставить туда shared_ptr. Вот мини пример.
void func(std::shared_ptr<uint64_t> ptr)
{
std::cout << "func: " << *ptr << "; " << "ptr use count: " << ptr.use_count() << std::endl; }
int main() {
ThreadPool pool(2);
pool.init();
auto ptr = std::make_shared<uint64_t>(20);
std::cout << "First use count: " << ptr.use_count() << std::endl;
auto res = pool.submit(func, ptr);
res.get();
std::cout << "Last use count: " << ptr.use_count() << std::endl;
pool.shutdown();
}Что умудряется тут увеличить счетчик у ptr на 1 лишний раз? Может и не лишний, но почему-то счетчик не возвращается снова к 1 после выполнения задачи из очереди и успешного ее извлечения.
Подозрение падает именно на то, что происходит функции submit.
Вывод программы:
First use count: 1
func: 20; ptr use count: 3
Last use count: 2
----------------------------------
А вот сама функция submit:
template<typename F, typename...Args>
auto submit(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()> wrapper_func = [task_ptr]() {
(*task_ptr)();
};
m_queue.enqueue(wrapperfunc);
m_conditional_lock.notify_one();
return task_ptr->get_future();
}

Google

Alexander
03.08.2018
18:14:44

Erik
03.08.2018
18:15:21

Alexander
03.08.2018
18:16:47
std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);

Mikhail Voronov
03.08.2018
18:19:13
std::function<void()> wrapper_func = [task_ptr]() {
(*task_ptr)();
};
m_queue.enqueue(wrapperfunc);
в последней строчке _ не пропущено случайно?

Erik
03.08.2018
18:20:11

Alexander
03.08.2018
18:20:11

Erik
03.08.2018
18:20:25

Alexander
03.08.2018
18:20:52
так то есть уже вас 3ка не смущает?
окей, теперь разбираемся с 2-кой

Mikhail Voronov
03.08.2018
18:31:31

Erik
03.08.2018
18:33:04
bool dequeue(T& t) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_queue.empty()) {
return false;
}
t = std::move(m_queue.front());
m_queue.pop();
return true;
}

Mikhail Voronov
03.08.2018
18:35:16
а он точно перед последним std::cout вызывается?

Google

/dev
03.08.2018
18:40:59

Dmitry
03.08.2018
18:41:22

Erik
03.08.2018
18:42:02
а он точно перед последним std::cout вызывается?
Это происходит внутри ThreadPool. Если есть задача в очереди - она автоматически извлекается dequeue. Потом она уже выполняется. И результат записывается в std::future. (В примере это переменная `res`).
Также в примере стоит ожидание результата в std::future ( res.get() ). Вывод уже после этого - значит извлечение точно уже было из очереди. :)

Dmitry
03.08.2018
18:43:53

Mikhail Voronov
03.08.2018
18:45:04


Erik
03.08.2018
18:47:24
Если написать вот такой код, то все работает как и должно было бы работать в хорошем случае. ?
void func(std::shared_ptr<uint64_t> ptr){
std::cout << "func: " << *ptr << "; " << "ptr use count: " << ptr.use_count() << std::endl;
}
int main() {
auto ptr = std::make_shared<uint64_t>(20);
{
ThreadPool pool(2);
pool.init();
std::cout << "First use count: " << ptr.use_count() << std::endl;
auto res = pool.submit(func, ptr); //.post(func, ptr);
res.wait();
pool.shutdown();
}
std::cout << "Last use count: " << ptr.use_count() << std::endl;
}
First use count: 1
func: 20; ptr use count: 3
Last use count: 1
Но это явно какой-то странный метод борьбы с утечкой :)

Alexander
03.08.2018
18:54:35
то есть тредпул у себя всё же прихранивает?

Erik
03.08.2018
18:55:12

Azoyan
03.08.2018
18:59:57

Aidar
03.08.2018
19:00:58
Какой нахрен init
Я знаю почему там 3

Mikhail Voronov
03.08.2018
19:05:41

Aidar
03.08.2018
19:05:44
Почему 2 хз
3 потомучто bind хранит значение

Erik
03.08.2018
19:08:11

Constantine
03.08.2018
19:10:31
Хочу объявить базовый класс, по сути являющийся концептом для policy (инстанцирование запрещено), как это нормально сделать? delete на деструктор дает варнинги у потомков

Aidar
03.08.2018
19:10:56
packaged_task умирает после того как в future появилось знаение

Erik
03.08.2018
19:11:45

Google

Mikhail Voronov
03.08.2018
19:11:54

Aidar
03.08.2018
19:11:55
Какой потерянный?

Dmitry
03.08.2018
19:12:00

Constantine
03.08.2018
19:12:17

Aidar
03.08.2018
19:12:30

Constantine
03.08.2018
19:12:47

Aidar
03.08.2018
19:12:52
Нет
Это не аналогично

Constantine
03.08.2018
19:13:12
я хочу эффект удаленного приватного деструктора - класс и никакой потомок не может быть инстанцирован

Aidar
03.08.2018
19:13:20
Хм

Erik
03.08.2018
19:13:29
Какой потерянный?
std::cout << "Last use count: " << ptr.use_count() << std::endl;возвращает 2, после тогда как уже был вызван .get()

Aidar
03.08.2018
19:13:31
А от полиси ващето надо наследоваться
По александреску
Так что хз

Dmitry
03.08.2018
19:13:57

Aidar
03.08.2018
19:14:01
Пекеджед
У тебя нет ожидания умирания таска
У тебя есть ожидание получения значения

Erik
03.08.2018
19:14:40

Google

Aidar
03.08.2018
19:14:49
Где

Constantine
03.08.2018
19:15:46
Хм... можно объявить чисто виртуальную final функцию

/dev
03.08.2018
19:16:14

Alexander
03.08.2018
19:16:42

Erik
03.08.2018
19:17:27
Где
ThreadPool извлекает задачу из очереди командой dequeue. Эта функция сразу вызывает .pop.

Dmitry
03.08.2018
19:17:38
Да, сочетание virtual final и abstract та ещё загадка для компилятора :)))

Aidar
03.08.2018
19:17:41
Покажи где ты ожидаешь dequeue
Я не увидел

/dev
03.08.2018
19:18:45

Erik
03.08.2018
19:18:49

Aidar
03.08.2018
19:18:54
Покажи где
Ты ждёшь фьючер из пекеджед таск
Но не dequeue

Mikhail Voronov
03.08.2018
19:20:27

Constantine
03.08.2018
19:20:32

Aidar
03.08.2018
19:20:32
Потенциально dequeue может завершиться позже а может и раньше того что второй поток просигналится

Mikhail Voronov
03.08.2018
19:20:53

Erik
03.08.2018
19:22:39
Покажи где
https://github.com/mtrebi/thread-pool/blob/master/include/ThreadPool.h строка 33
Да, submit мне возвращает соответсвующий std::future.
В main.cpp я жду когда в std::future появится результат res.get(). К этому моменту из очереди dequeue уже точно должен был извлечь и выполнить нужную операцию.

Aidar
03.08.2018
19:22:52
Ну ок тут это не dequeue а кусок цикла воркера
Несуть

Google

Aidar
03.08.2018
19:24:42

Mikhail Voronov
03.08.2018
19:25:13

Aidar
03.08.2018
19:25:19
Молодец

Mikhail Voronov
03.08.2018
19:25:53
тут не я молодец, а автор вопроса теряет время)

Aidar
03.08.2018
19:26:08
Либа так себе
Какой нахрен init
Руки оторвать

Dmitry
03.08.2018
19:26:46
Может проблема в том что get future зовётся с гонкой?

Constantine
03.08.2018
19:26:49

Aidar
03.08.2018
19:29:59
Rly

Dmitry
03.08.2018
19:31:36
Флаг остановки не атомик
И ещё future overdesign

Aidar
03.08.2018
19:32:18
decltype(f(args...)) Foo=f(forward(args)...)

Dmitry
03.08.2018
19:32:40
Это опция которую можно в таск завернуть снаружи.

Constantine
03.08.2018
19:37:35