Skip to content

Instantly share code, notes, and snippets.

@kennykerr
Last active January 30, 2019 23:48
Show Gist options
  • Save kennykerr/13082fbb4b6502fd7fa9570a896db4f0 to your computer and use it in GitHub Desktop.
Save kennykerr/13082fbb4b6502fd7fa9570a896db4f0 to your computer and use it in GitHub Desktop.
How to use a private thread pool with a C++ coroutine
#include "winrt/Windows.Foundation.h"
#include <windows.h>
using namespace winrt;
using namespace Windows::Foundation;
struct private_pool
{
private_pool() :
m_pool(check_pointer(CreateThreadpool(nullptr)))
{
InitializeThreadpoolEnvironment(&m_environment);
SetThreadpoolCallbackPool(&m_environment, m_pool.get());
}
void thread_limits(uint32_t const high, uint32_t const low)
{
SetThreadpoolThreadMaximum(m_pool.get(), high);
check_bool(SetThreadpoolThreadMinimum(m_pool.get(), low));
}
~private_pool() noexcept
{
DestroyThreadpoolEnvironment(&m_environment);
}
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
void await_suspend(std::experimental::coroutine_handle<> handle)
{
if (!TrySubmitThreadpoolCallback(callback, handle.address(), &m_environment))
{
throw_last_error();
}
}
private:
static void WINRT_CALL callback(PTP_CALLBACK_INSTANCE, void* context) noexcept
{
std::experimental::coroutine_handle<>::from_address(context)();
}
struct pool_traits
{
using type = PTP_POOL;
static void close(type value) noexcept
{
CloseThreadpool(value);
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
handle_type<pool_traits> m_pool;
TP_CALLBACK_ENVIRON m_environment;
};
struct Queue
{
private_pool m_pool;
Queue()
{
m_pool.thread_limits(1, 1);
}
IAsyncAction Async(delegate<> callback)
{
// This uses the default process-wide thread pool.
// co_await resume_background();
// This uses the private m_pool thread pool. Just
// remember that the pool must outlive the coroutine.
co_await m_pool;
callback();
}
};
int main()
{
init_apartment();
Queue queue;
std::vector<IAsyncAction> results;
for (uint32_t item{}; item < 20; ++item)
{
results.push_back(queue.Async([=]
{
printf("Item=%d Thread=%d\n", item, GetCurrentThreadId());
}));
}
puts("Queued");
for (auto&& async : results)
{
async.get();
}
puts("Done");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment