Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What I'm doing wrong here ?

79 views
Skip to first unread message

Bonita Montero

unread,
Dec 6, 2020, 9:23:02 AM12/6/20
to
using namespace std;
using void_task = packaged_task<void()>;
using task_ptr = shared_ptr<void_task>;
deque<task_ptr> dq;
dq.emplace_back( make_shared<void_task>( bind( []() {} ) ) );
auto front = dq.pop_front();

Bonita Montero

unread,
Dec 6, 2020, 10:06:27 AM12/6/20
to
How should I do the dequeuing ?

#include <future>
#include <deque>

using namespace std;

using void_task = packaged_task<void()>;
using task_ptr = shared_ptr<void_task>;
using task_queue = deque<task_ptr>;

template<typename F, typename ... Args>
void enqueue( task_queue &dq, F &&f, Args &&...args )
{
dq.emplace_back( make_shared<void_task>( bind( forward<F>( f ),
forward<Args>( args ) ... ) ) );
}

task_ptr dequeue( task_queue &dq )
{
return dq.pop_front();
}

int main()
{
auto l = []( int &a )
{
++a;
};
deque<task_ptr> dq;
int i = 0;
enqueue( dq, l, i );
task_ptr pTask = dequeue( dq );
}


Öö Tiib

unread,
Dec 6, 2020, 10:11:47 AM12/6/20
to
On Sunday, 6 December 2020 at 16:23:02 UTC+2, Bonita Montero wrote:

Not saying what you want to do and all #includes are missing and likely
most of code too. That is what you always do ... but it is wrong. So all we
can tell are simple syntax errors but your compiler tells that as well.

> using namespace std;
> using void_task = packaged_task<void()>;
> using task_ptr = shared_ptr<void_task>;
> deque<task_ptr> dq;
> dq.emplace_back( make_shared<void_task>( bind( []() {} ) ) );

That line can't be just like that It has to be inside of function.

> auto front = dq.pop_front();

You plan to create void variable using auto? That does not work.

Bonita Montero

unread,
Dec 6, 2020, 10:23:15 AM12/6/20
to
>> auto front = dq.pop_front();

> You plan to create void variable using auto? That does not work.

The dequeued entity should be a task_ptr.

Öö Tiib

unread,
Dec 6, 2020, 10:28:40 AM12/6/20
to
I do not get what you mean ... deque::pop_front is void:
<https://en.cppreference.com/w/cpp/container/deque/pop_front>

Bonita Montero

unread,
Dec 6, 2020, 10:38:53 AM12/6/20
to
>>> You plan to create void variable using auto? That does not work.
>> The dequeued entity should be a task_ptr.

> I do not get what you mean ... deque::pop_front is void:
> <https://en.cppreference.com/w/cpp/container/deque/pop_front>

Sorry, I didn't check the docs and thought that it returns
the frontmost element.

So this way everything is o.k.:

#include <future>
#include <deque>
#include <utility>

using namespace std;

using void_task = packaged_task<void()>;
using task_ptr = shared_ptr<void_task>;
using task_queue = deque<task_ptr>;

template<typename F, typename ... Args>
void enqueue( task_queue &dq, F &&f, Args &&...args )
{
dq.emplace_back( make_shared<void_task>( bind( forward<F>( f ),
forward<Args>( args ) ... ) ) );
}

task_ptr dequeue( task_queue &dq )
{
task_ptr front = move( dq.front() );
dq.pop_front();
return front;

Öö Tiib

unread,
Dec 6, 2020, 12:37:11 PM12/6/20
to
On Sunday, 6 December 2020 at 17:38:53 UTC+2, Bonita Montero wrote:
> >>> You plan to create void variable using auto? That does not work.
> >> The dequeued entity should be a task_ptr.
>
> > I do not get what you mean ... deque::pop_front is void:
> > <https://en.cppreference.com/w/cpp/container/deque/pop_front>
> Sorry, I didn't check the docs and thought that it returns
> the frontmost element.
>
> So this way everything is o.k.:

May be. Why you have those shared_ptrs instead of having
deque<void_task> directly.

Bonita Montero

unread,
Dec 6, 2020, 1:41:02 PM12/6/20
to
>> So this way everything is o.k.:

> May be. Why you have those shared_ptrs instead of having
> deque<void_task> directly.

I don't want to move the task-parameters.

Öö Tiib

unread,
Dec 6, 2020, 2:48:54 PM12/6/20
to
What it means? These are not moved but pointers to those
are. So without explaining it feels like
std::deque<std::shared_ptr<std::string>> that is added
inefficiency without benfits on general case.

Bonita Montero

unread,
Dec 6, 2020, 3:24:17 PM12/6/20
to
>> I don't want to move the task-parameters.

> What it means? These are not moved but pointers to those
> are. So without explaining it feels like
> std::deque<std::shared_ptr<std::string>> that is added
> inefficiency without benfits on general case.

The parameters encapsulated in a packaged task would be moved if i
move the packaged task. Depending on the length of the parameter-set
that might have a higher overhead than moving just a pointer.

Bonita Montero

unread,
Dec 6, 2020, 3:27:44 PM12/6/20
to
So here's my little thread-pool engine:
First a little debug-header:

// debug_exceptions.h
#pragma once
#if !defined try_debug
#if !defined(NDEBUG)
#define try_debug try
#else
#define try_debug
#endif
#endif
#if !defined catch_debug
#if !defined(NDEBUG)
#define catch_debug(stmt) catch( stmt )
#else
#define catch_debug(stmt) if( false )
#endif
#endif

// thread-pool-engine
#include <thread>
#include <deque>
#include <future>
#include <utility>
#include <functional>
#include <memory>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <cassert>
#include "debug_exceptions.h"

#if defined(_MSC_VER)
#pragma warning(disable: 26117)
#endif

struct thread_pool
{
thread_pool( unsigned maxThreads );
~thread_pool();
void stop();
void resize( unsigned maxThreads );
void clear_queue();
template<typename F, typename ... Args>
void enqueue_task( F &&f, Args &&...args );

private:
using void_task = std::packaged_task<void()>;
using task_ptr = std::shared_ptr<void_task>;
unsigned m_maxThreads;
std::mutex m_mtx;
unsigned m_stop;
std::vector<std::thread> m_threads;
std::condition_variable m_queueCv;
unsigned m_nThreadsRunning;
std::deque<task_ptr> m_taskQueue;

void theThread( std::size_t threadIndex );
};

thread_pool::thread_pool( unsigned maxThreads ) :
m_maxThreads( maxThreads ),
m_stop(),
m_nThreadsRunning( 0 )
{
m_threads.reserve( maxThreads );
}

thread_pool::~thread_pool()
{
using namespace std;
{
lock_guard<mutex> lock( m_mtx );
m_stop = (int)m_threads.size();
m_queueCv.notify_all();
}
for( thread &t : m_threads )
t.join();
}

void thread_pool::stop()
{
using namespace std;
lock_guard<mutex> lock( m_mtx );
m_stop = (unsigned)m_threads.size();
m_queueCv.notify_all();
}

void thread_pool::resize( unsigned maxThreads )
{
using namespace std;
lock_guard<mutex> lock( m_mtx );
unsigned nCurThreads = (unsigned)m_threads.size();
if( maxThreads >= nCurThreads )
m_threads.reserve( maxThreads ),
m_maxThreads = maxThreads;
else
{
unsigned stop = nCurThreads - maxThreads;
m_stop += stop;
for( ; stop; m_queueCv.notify_one(), --stop );
}
}

void thread_pool::clear_queue()
{
using namespace std;
lock_guard<mutex> lock( m_mtx );
m_taskQueue.clear();
}

template<typename F, typename ... Args>
void thread_pool::enqueue_task( F &&f, Args &&...args )
{
using namespace std;
auto threadProxy = []( thread_pool *tp, size_t threadIndex )
{
tp->theThread( threadIndex );
};
lock_guard<mutex> lock( m_mtx );
m_taskQueue.emplace_back( make_shared<void_task>( bind( forward<F>( f
), forward<Args>( args ) ... ) ) );
if( m_nThreadsRunning == m_threads.size() && m_nThreadsRunning <
m_maxThreads )
m_threads.emplace_back( threadProxy, this, m_threads.size() );
m_queueCv.notify_one();
}

void thread_pool::theThread( size_t threadIndex )
{
using namespace std;
unique_lock<mutex> lock( m_mtx );
for( ; ; )
{
task_ptr task;
for( ; ; )
{
if( m_taskQueue.size() != 0 )
{
task = move( m_taskQueue.front() );
m_taskQueue.pop_front();
++m_nThreadsRunning;
lock.unlock();
break;
}
if( m_stop )
{
m_threads[threadIndex].detach();
m_threads.erase( m_threads.begin() + threadIndex );
--m_stop;
return;
}
m_queueCv.wait( lock );
}
future<void> fut = task->get_future();
try_debug
{
fut.get();
}
catch_debug( ... )
{
assert(false);
}
lock.lock();
--m_nThreadsRunning;
}
}

Bonita Montero

unread,
Dec 6, 2020, 3:42:34 PM12/6/20
to
Should be:
if( m_nThreadsRunning == m_threads.size() && m_threads.size() <

Öö Tiib

unread,
Dec 6, 2020, 6:07:18 PM12/6/20
to
That sounds like saying that move from long std::string is
expensive because there are lot of characters to move.
The std::shared_ptr is expensive and so if its features are
not needed then it is pointless waste of resources into
unneeded complexity.

.

Bonita Montero

unread,
Dec 6, 2020, 8:13:26 PM12/6/20
to
> That sounds like saying that move from long std::string is
> expensive because there are lot of characters to move.
> The std::shared_ptr is expensive and so if its features are
> not needed then it is pointless waste of resources into
> unneeded complexity.

No, shared_ptr isn't expensive.
But not all data-types inside the task-objects might be moveable.

Bonita Montero

unread,
Dec 7, 2020, 8:29:27 AM12/7/20
to
> That sounds like saying that move from long std::string is
> expensive because there are lot of characters to move.
> The std::shared_ptr is expensive and so if its features are
> not needed then it is pointless waste of resources into
> unneeded complexity.

And even more: the parameters inside the packaged task might
not have a move-constructor or move-assignment-operator !

Öö Tiib

unread,
Dec 7, 2020, 9:50:47 AM12/7/20
to
No. The actual issue is likely that you use defective packaged_task
of Visual Studio. They refuse to fix it:
<https://developercommunity.visualstudio.com/content/problem/108672/unable-to-move-stdpackaged-task-into-any-stl-conta.html>
But you just post nonsense instead of saying that
like usual.

spu...@isnotyourbuddy.co.uk

unread,
Dec 7, 2020, 10:37:19 AM12/7/20
to
If that hideous line noise in stackoverflow is the answer then someone is
asking the wrong question. Probably written by Alf or one of his diciples.

Bonita Montero

unread,
Dec 7, 2020, 10:38:51 AM12/7/20
to
> No. The actual issue is likely that you use defective packaged_task
> of Visual Studio. They refuse to fix it:
> <https://developercommunity.visualstudio.com/content/problem/108672/unable-to-move-stdpackaged-task-into-any-stl-conta.html>
> But you just post nonsense instead of saying that
> like usual.

He is packaging the task incorrectly.

Chris M. Thomasson

unread,
Dec 7, 2020, 10:46:40 PM12/7/20
to
On 12/6/2020 5:13 PM, Bonita Montero wrote:
>> That sounds like saying that move from long std::string is
>> expensive because there are lot of characters to move.
>> The std::shared_ptr is expensive and so if its features are
>> not needed then it is pointless waste of resources into
>> unneeded complexity.
>
> No, shared_ptr isn't expensive.

Ummm.... atomic RMW's and memory barriers are expensive.

Bonita Montero

unread,
Dec 8, 2020, 1:37:02 AM12/8/20
to
>> No, shared_ptr isn't expensive.

> Ummm.... atomic RMW's and memory barriers are expensive.

20 cycles on my computer - that's nothing.

Chris M. Thomasson

unread,
Dec 8, 2020, 9:16:15 PM12/8/20
to
That is a rather naive statement. Humm... Why do you think split
counters were invented? Why do you think RCU was invented? Well, to get
rid of atomic RMW's and memory barriers. ;^)

Bonita Montero

unread,
Dec 9, 2020, 2:58:04 AM12/9/20
to
>>> Ummm.... atomic RMW's and memory barriers are expensive.

>> 20 cycles on my computer - that's nothing

> That is a rather naive statement. Humm... Why do you think split
> counters were invented? Why do you think RCU was invented? Well,
> to get rid of atomic RMW's and memory barriers. ;^)

What you saying here has nothing to do what I did.

Scott Lurndal

unread,
Dec 9, 2020, 9:55:46 AM12/9/20
to
Try not to feed the troll.

Bonita Montero

unread,
Dec 9, 2020, 10:50:58 AM12/9/20
to
>> That is a rather naive statement. Humm... Why do you think split
>> counters were invented? Why do you think RCU was invented? Well,
>> to get rid of atomic RMW's and memory barriers. ;^)

> Try not to feed the troll.

I'm not trolling. Handing over a queue-item to another thread is so
expensive, that 20 cycles don't hurt.

Chris M. Thomasson

unread,
Dec 9, 2020, 2:52:58 PM12/9/20
to
Its difficult because it can mislead others. Her statements on this seem
to be naive at best. Sometimes I think she knows better.
0 new messages